zoukankan      html  css  js  c++  java
  • Elasticsearch JVM Heap Size大于32G,有什么影响?

    0、引言

    在规划ES部署的时候,会涉及到data node的分配堆内存大小,而Elasticsearch默认安装后设置的内存是1GB,对于任何一个业务部署来说,这个都太小了。

    设置Heap Size的方式有两种,现将参考文献[1]摘录如下:

    1)  指定ES_HEAP_SIZE环境变量。服务进程在启动时候会读取这个变量,并相应的设置堆的大小。

    export ES_HEAP_SIZE=10g

    2) 命令行参数的形式,在程序启动的时候把内存大小传递给它

    ./bin/elasticsearch -Xmx10g -Xms10g
    

    这里的xmx和xms以前常用,但是究竟为什么要事先分配?参考文献[2]中的几个点我觉得讲的吼啊,我整理下:

    a) -Xms和-Xmx设置相同时可避免Java堆自动扩展

    b) 大部分 GC 算法依赖于被分配为连续的内存块的堆,因此不能在堆需要扩大时再分配更多本机内存。所有堆内存必须预先保留

    c) Xmx指定内存并不是真正的分配,而是一种保留,内存保留 != 内存分配。即预先跑马圈地,并没有实际都用到。例如Xmx=512M是直接预留出512M的内存空间,但启动时的Java进程并不一定全部使用,但512M是它的“领地”。

    1、那么将Java Heap Size设置的大于32G会对性能有什么影响?

    开门见山的说,结果有几点(这几点其实也是内部关联):

    • 触发JVM的临界值,优化策略Compressed OOPS失效(之前Heap Size在[4G~32G]区间内采用此优化)
    • 由于优化策略失效,同时堆内存>32G,所以JVM被迫使用8字节(64位)来对Java对象寻址(之前4字节(32位)就够了)
    • 通常64位JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(事实上当内存到达40-50GB的时候,有效内存才相当于使用Compressed OOPS技术时候的32G内存)
    • 更大的指针在主内存和缓存器(例如LLC, L1等)之间移动数据的时候,会占用更多的带宽(参考文献[1]中表示很糟糕)
    • 让JVM的GC面临更大压力的指针对象(在实际应用中构建大于12-16G的堆时,若无很好的性能调优与测评,你很容易就会引起一个耗时数分钟的完全GC)

    1.1 JVM的OOPS

    OOP = “ordinary object pointer” 普通对象指针

    启用CompressOops后,会压缩的对象:

    • 每个class的属性指针(静态成员变量)
    • 每个对象的属性指针
    • 普通对象数组的每个元素指针

    1.2 JVM的优化策略Compressed OOPS

    从JDK 1.6 update14开始,64 bit JVM正式支持了 -XX:+UseCompressedOops ,这个可以压缩指针,起到节约内存占用的新参数。

    Compressed OOPS,即大雾的对象压缩技术,压缩引用到32位,以降低堆的占用空间。其伪代码原理就不贴了,在参考文献[3]中,大家自取。

    在堆大小在[4G~32G]的时候,这项技术会被触发,在JVM执行时加入编/解码指令,即

    JVM在将对象存入堆时编码,在堆中读取对象时解码

    内存地址确定公式类似于

    <narrow-oop-base(64bits)> +(<narrow-oop(32bits)><< 3) +<field-offset>
    

    Zero Based Compressed OOPS(零基压缩优化)则进一步将基地址置为0(并不一定是内存空间地址为0,只是JVM相对的逻辑地址为0,如可用CPU的寄存器相对寻址) 这样转换公式变为:

    (<narrow-oop << 3) +<field-offset>
    

    从而进一步提高了压解压效率。

    参考文献[1]中举一个简单的例子,有点像BitMap的思想,即

    使用Zero Based Compressed OOPS后,它的指针不再表示对象在内存中的精确位置,而是表示偏移量。这意味着32位的指针可以引用40亿个对象,而不是40亿个字节。

    1.3 Zero Based Compressed OOPS的多种策略

    它可以针对不同的堆大小使用多种策略,具体可以 ps + grep查看:

    • 堆小于4G,无需编/解码操作,JVM会使用低虚拟地址空间(low virutal address space,64位下模拟32位)
    • 小于32G而大于4G,使用Zero Based Compressed OOPS
    • 大于32G,不使用Compressed OOPS

    2、结论

    • Compressed OOPS,可以让跑在64位平台下的JVM,不需要因为更宽的寻址,而付出Heap容量损失的代价
    • 它的实现方式是在机器码中植入压缩与解压指令,可能会给JVM增加额外的开销
    • 如果希望更大的堆内存。可以考虑一台机器上创建两个或者更多ES节点(封顶32G堆内存),而不要部署一个使用32+GB内存的节点(仍然要坚持50%原则)

    999、参考文献

    [1] Elasticsearch 合理内存分配

    [2]【原创】深入理解Java堆内存分配策略(Xmx和Xms)

    [3] 主题:JVM优化之压缩普通对象指针(CompressedOops)

    [4] Java虚拟机优化选项,GC说明

    [5] 应该使用32位还是64位的JVM?

  • 相关阅读:
    获取ocx运行路径的另一种方法
    使用D3D渲染YUV视频数据
    C++(MFC)中WebBrowser去除3D边框的方法(实现IDocHostUIHandler接口)
    ActiveX控件的安全初始化和脚本操作 和 数字签名SIGN
    解决Eclipse中的卡死现象
    Http请求头和响应头
    HTTP请求头与响应头
    centos7 Mariadb5.5升级到Mariadb10.2
    window下利用navicat访问Linux下的mariadb数据库
    在Linux上安装及配置MariaDB
  • 原文地址:https://www.cnblogs.com/zklidd/p/6170917.html
Copyright © 2011-2022 走看看