首页 > 系统相关 >[转帖]JVM之指针压缩&内存如何设置

[转帖]JVM之指针压缩&内存如何设置

时间:2024-03-26 15:25:53浏览次数:21  
标签:32 压缩 转帖 64 内存 JVM 指针

https://www.cnblogs.com/liang1101/p/12727754.html

 

  在32位到64位的转变中,人们最大的获益是内存容量。在一个32位的系统中,内存地址的宽度就是32位,这就意味着,我们最大能获取的内存空间是2^32(也就是4G)字节。这个容量明显不够用!在一个64位的机器中,理论上,我们能获取到的内存容量是2^64字节,这是一个十分庞大的数字。可惜的是,这只是一个理论值,而现实中,因为有一堆有关硬件和软件的因素限制,我们能得到的内存要少得多。举个例了来说,最好的 linux 系统最多支持到16TB的内存,而且截止到现在 java11 也在正在研制最新一代的垃圾收集器 ZGC ,号称可以支持到 TB 几倍的且能保证 STW 时间不会太长,可能许多人会说“16TB好大呀”,但是和2^64比起来,它真的挺小的。好了,接下来,我们就谈谈compressed oops能帮我们做什么。

什么是 OOP ?

  在堆中,32位的对象引用(指针)占4个字节,而64位的对象引用占8个字节。64位JVM在支持更大堆的同时,由于对象引用变大却带来了性能问题:

  1. 增加了GC开销:64位对象引用需要占用更多的堆空间,留给其他数据的空间将会减少,从而加快了GC的发生,更频繁的进行GC。
  2. 降低CPU缓存命中率:64位对象引用增大了,CPU能缓存的oop将会更少,从而降低了CPU缓存的效率。

  为了能够保持32位的性能,oop必须保留32位。那么,如何用32位oop来引用更大的堆内存呢?答案是——压缩指针(CompressedOops)。

  OOP = “ordinary object pointer” 普通对象指针。 启用CompressOops后,会压缩的对象:

    1. 每个Class的属性指针(静态成员变量)

    2. 每个对象的属性指针

    3. 普通对象数组的每个元素指针

  当然,压缩也不是万能的,针对一些特殊类型的指针,JVM是不会优化的。 比如指向 PermGen的Class 对象指针,本地变量,堆栈元素,入参,返回值,NULL指针不会被压缩

1)CompressedOops原理:

  JVM的实现方式是,不再保存所有引用,而是每隔8个字节保存一个引用。例如,原来保存每个引用0、1、2...,现在只保存0、8、16...。因此,指针压缩后,并不是所有引用都保存在堆中,而是以8个字节为间隔保存引用。

  CompressedOops,可以让跑在64位平台下的JVM,不需要因为更宽的寻址,而付出Heap容量损失的代价。 不过它的实现方式是在机器码中植入压缩与解压指令,可能会给JVM增加额外的开销。

2)零基压缩优化(Zero Based Compressd Oops)

  零基压缩是针对 压、解压 动作的进一步优化。 它通过改变正常指针的随机地址分配特性,强制堆地址从零开始分配(需要OS支持),进一步提高了压解压效率。要启用零基压缩,你分配给JVM的内存大小必须控制在4G以上,32G以下。

3)总结:

  • 如果GC堆大小在 4G以下,直接砍掉高32位,避免了编码解码过程;
  • 如果GC堆大小在 4G以上32G以下,则启用 UseCompressedOop;
  • 如果GC堆大小 大于32G,压指失效,使用原来的64位(所以说服务器内存太大不好......)。

灵魂提问

  从以上结果中我们知道 32GB 以下是启用了 UseCompressedOop,但是当我们线上真正启动服务的时候直接设置 -Xmx=32GB 的时候很可能导致 CompressedOop 失效,那我们怎么确定当前环境下最大内存设置多大才且最大限度的使用内存才能启动 CompressedOop 呢?

  32G是个近似值,这个临界值跟JVM和平台有关。如果不想精确设置的话,31G是个绝对安全的数值,31G肯定默认开启compressed oops。我们可以通过增加JVM参数 -XX:+PrintFlagsFinal,验证UseCompressedOops的值,从而得知,到底是不是真的开启了压缩指针,还是压缩指针失效!
  那我们就手动来验证这个临界值:

  32G,即32*1024=32768M,刚好在范围[32760, 32770]中。而 32768m 验证后得到并没有开启压缩指针,所以可以从 32760 ~ 32768 之间验证选择一个最大的且开启压缩指针的内存大小。

简单测试验证

  我们来做了一个简单测试,验证一下这个问题:分配设置内存大小分别为:-Xmx32760m 和 -Xmx32770m,-Xmn 都是 100M(S0:S1:Eden默认1:1:8)。总计分配一个包含8个对象类型和8个原子类型以及String,总计17个类型属性的对象 1kw 次。看它们分别触发了多少 YGC,结论如下表所示:
实验次数    开启压缩指针YGC次数    关闭压缩指针YGC次数

 

   由执行结果可知,Young区完全一样的情况下,开启压缩指针相比关闭压缩指针,能节省20%多的内存。由此可知,32G还真是一个奇妙的魔法数值!另外需要说明的是YGC次数有小数,是表示Eden区占用比例,比如 17.52 次 YGC 表示发生了 17次 YGC 并且 Eden 还占了52%

标签:32,压缩,转帖,64,内存,JVM,指针
From: https://www.cnblogs.com/jinanxiaolaohu/p/18096720

相关文章

  • c++栈内存溢出问题
    问题说明实验课测量快排时间时,用intar[MAXSIZE+1];来创建数组,数据规模从1000-10000,而MAXSIZE的设置不能超过600000,超过了程序就无法运行直接中断,理论上这是不应该。程序中用rand()生成随机数据,但若对数据求模rand()%100,则程序运行到中途会异常中断。问题原因intar[M......
  • JVM的一些小记
    把最近的一些从jvm原理书中的一些摘要记一下JVM1.对象的内存布局是什么样子?对象在堆内存中的存储布局可以划分3个部分,对象头,实例数据,对齐填充。对象头包括两个部分,第一是对象的运行时数据,如对象哈希码,GC分代年龄,锁状态等,这部分称作MarkWord。第二是类型指针,java通过......
  • 面试类-JVM原理(四)
    说说解释执行和编译执行的区别(补充)先说解释和编译的区别:解释:将源代码逐行转换为机器码。编译:将源代码一次性转换为机器码。一个是逐行,一个是一次性,再来说说解释执行和编译执行的区别:解释执行:程序运行时,将源代码逐行转换为机器码,然后执行。编译执行:程序运行前,将源代码一次......
  • C语言中整数和浮点数在内存中的存储
    一、整数在内存中的存储我们知道整数的二进制表示形式有三种,原码、反码、补码。三种表示方法均由符号位和数值位两部分构成,符号位用0表示正,用1表示负,最高一位被当作符号位,其余位被当作数值位。其中,正整数的原码、反码、补码三种表示相同负整数的原码:对应10进制数直接转换过......
  • C语言-内存函数
    文章目录1.memcpy1.1.memcpy语法形式1.2.memcpy的模拟实现2.memmove2.1.memmove的语法形式2.2.memmove的模拟实现3.memset3.1.memset的语法形式4.memcmp4.1.memcmp的语法形式1.memcpy1.1.memcpy语法形式void*memcpy(void*destinotion,const*source,size_tnu......
  • C++动态内存管理
    目录C/C++内存分配C++内存管理C++内存管理介绍C++内存管理使用C++内存管理基本语法operatornew和operatordelete函数定位new表达式(placement-new)基本语法使用场景malloc/free和new/delete相同点不同点C/C++内存分配在C语言动态内存管理章节已经了解到内......
  • Java的方法、重载、递归、内存
    一、方法什么是方法方法:一堆代码的集合,一般完成了某个特定的功能,当我们再次使用这个方法的时候,就等于使用了这些代码。方法目的:代码复用,提高程序灵活度,易维护,易扩展。方法的声明修饰符列表  返回值类型  方法名 (参数列表){ 方法体 }注意事项修饰符列表 ......
  • JVM高频面试题---垃圾回收(3)
    JVM(3)垃圾回收对象什么时候可以被垃圾器回收?JVM垃圾回收算法有哪些?说一下JVM的分代回收说一下JVM有哪些垃圾回收器详细说一下G1垃圾回收器强引用、软引用、弱引用、虚对象......
  • 每日面经分享(操作系统:内存、缓存、硬盘)
    1.用户态和内核态的区别a.用户态和内核态是操作系统中的两种不同的执行模式,用于区分应用程序代码和操作系统内核代码的权限和特权级别。b.用户态是指应用程序运行时所处的执行模式。在用户态下,应用程序只能访问受限资源和执行受限操作,无法直接访问底层硬件或执行特权操......
  • 清理系统centos下缓存并释放内存
    问题描述在启动容器的时候报错Exceptioninthread"main"java.lang.RuntimeException:startingjavafailedwith[1]output:##ThereisinsufficientmemoryfortheJavaRuntimeEnvironmenttocontinue.#Nativememoryallocation(mmap)failedtomap832988774......