JVM调参、GCRoots与四大引用浅析

Java8 JVM内存结构

基本结构与之前类似,只是Java8取消了之前的“永久代”,取而代之的是“元空间”——Metaspace,两者本质是一样的。“永久代”使用的是JVM的堆内存,而“元空间”是直接使用的本机物理内存。

GC Roots

如果判断一个对象可以被回收?

引用计数算法

维护一个计数器,如果有对该对象的引用,计数器+1,反之-1。无法解决循环引用的问题。

可达性分析算法

枚举根节点做可达性分析。即,从一组名为“GC Roots”的根节点(起始点)对象出发,向下遍历。那些没有被遍历到与GC Roots形成通路的对象,会被标记为“回收”(可达判断为存活,不可达判为死亡)。所谓的“GC roots”或者说tracing GC的“集合”,就是一组必须活跃的引用

哪些对象可以作为GC Roots?

可以作为GC Roots举例:

    1. 本地方法栈(native)中引用的对象。


    1. 虚拟机栈(栈帧中的局部变量)中引用的对象。
    1. 方法区中常量引用的对象。
    1. 方法区中类静态属性引用的对象。


JVM参数

JVM 三种类型参数

    1. 标配参数(了解)
    1. X参数(了解)
    1. XX参数(重要)

标配参数

比如-version-help-showversion等,几乎不会改变。

X参数

用得不多,比如-Xint,解释执行模式;-Xcomp,编译模式(第一次使用就编译成本地代码);-Xmixed,开启混合模式(默认,先编译再执行)。

XX参数

重要,用于JVM调优。

JVM XX参数

XX参数包括:

  • Boolean类型
  • kv设值类型(键值对)

jinfo (查看当前运行程序的配置)

布尔类型

公式-XX:+某个属性-XX:-某个属性,开启(+)或关闭(-)某个功能。比如-XX:+PrintGCDetails,开启GC详细信息。

KV键值类型

公式-XX:属性key=值value。比如-XX:Metaspace=128m-XX:MaxTenuringThreshold=15

JVM Xms/Xmx参数

-Xms-Xmx十分常见,用于设置初始堆大小最大堆大小。第一眼看上去,既不像X参数,也不像XX参数。实际上-Xms等价于-XX:InitialHeapSize-Xmx等价于-XX:MaxHeapSize。所以-Xms-Xmx属于XX参数。

JVM 查看参数

查看某个参数

使用jps -l配合jinfo -flag JVM参数 pid 。先用jsp -l查看java进程,选择某个进程号。

17888 org.jetbrains.jps.cmdline.Launcher
5360 org.jetbrains.idea.maven.server.RemoteMavenServer
18052 demo3.demo3

jinfo -flag PrintGCDetails 18052可以查看18052 Java进程的PrintGCDetails参数信息。

-XX:-PrintGCDetails

JVM参数调优:查看参数(第三个重要)

上面查看参数时使用参数-flag/flags,得需要具体的进程号,下面的这些不用,并且非常重要:

  • java -XX:+PrintFlagsInitial,查看JVM初始参数
  • java -XX:+PrintFlagsFinal查看修改更新后的参数

    使用java -XX:+PrintFlagsFinal打印中的结果有 =:=两种,如下:

    =就是没有被修改过的值,:=就是被JVM默认加载的时候或者人为修改的参数
  • java -XX:+PrintCommandLineFlags -version打印命令行参数,可以方便查看使用的是那个垃圾回收器

JVM 常用参数

-Xmx/-Xms

如何解释 -Xmx和-Xms,属于X参数还是XX参数?

  • -Xms等价于-XX:InitialHeapSize
  • -Xmx等价于-XX:MaxHeapS

最大和初始堆大小。最大默认为物理内存的1/4,初始默认为物理内存的1/64。

-Xss

等价于-XX:ThresholdStackSize,查看栈空间的大小(栈管运行,堆管存储)。用于设置单个栈的大小,系统默认值是0(不代表栈大小真的为0,而是代表是系统的默认值512k~1024k)。而是根据操作系统的不同,有不同的值。比如64位的Linux系统是1024K,而Windows系统依赖于虚拟内存。

-Xmn

新生代大小,一般不调。

-XX:MetaspaceSize

设置元空间大小。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。默认大概是用了20M的大小

-XX:+PrintGCDetails

输出GC收集信息,包含GCFull GC信息。这个比较重要。

-XX:SurvivorRatio

新生代中,Eden区和两个Survivor区的比例,默认是8:1:1。通过-XX:SurvivorRatio=4改成4:1:1

-XX:NewRatio

老生代和新年代的比列,默认是2,即老年代占2,新生代占1。如果改成-XX:NewRatio=4,则老年代占4,新生代占1。

-XX:MaxTenuringThreshold

新生代设置进入老年代的时间,默认是新生代逃过15次GC后,进入老年代。如果改成0,那么对象不会在新生代分配,直接进入老年代。并且,自己设置的时候,最大值不能超过15。

以上参数使用示例:

  1. 使用jps查看进程信息


  2. 以元空间举例,查看初始元空间大小


  3. 改变元空间大小


  4. 重新查看元空间大小


四大引用

以下Demo都需要设置-Xmx-Xms(手动设为10M),不然系统默认很大,很难演示。

强引用

当内存不足,JM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收。强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达
状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一

使用new方法创造出来的对象,默认都是强引用。GC的时候,就算内存不够,抛出OutOfMemoryError也不会回收对象,死了也不回收

package Test;

public class T{

    public static void main(String[] args) {
        //定义强引用
        Object A = new Object();
        //引用复制,B也为强引用
        Object B = A;

        //A置空
        A = null;
        //手动垃圾回收
        System.gc();
        //B不会被回收,A会
        System.out.println(B);
    }
}


/*====================output========================
java.lang.Object@4554617c
 */

软引用

需要用Object.Reference.SoftReference来显示创建如果内存够,GC的时候不回收内存不够则回收,尽量不让其发生OOM。常用于内存敏感的应用,比如高速缓存。详见SoftReferenceDemo

弱引用

需要用Object.Reference.WeakReference来显示创建无论内存够不够,只要是弱引用,GC的时候都会回收,也可以用在高速缓存上。详见WeakReferenceDemo

软引用和弱引用的适用场景:
假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取则会严重影响性能,如果一次性全部加载到内存中又可能造成内存溢出,此时使用软引用可以解决这个问题。

设计思路是:用一个 HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。
Map<String,SoftReference< Bitmap>> imageCache = new HashMap<String,SoftReference<Bitmap>>();

WeakHashMap

传统的HashMap就算key==null了,也不会回收键值对。但是如果是WeakHashMap,一旦内存不够用时,且key==null时,会回收这个键值对。详见WeakHashMapDemo

虚引用

需要用Object.Reference.PhantomReference类来显示创建。顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列( Reference queue)联合使用。

虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被 finalize以后,做某些事情的机制。软应用和弱引用可以通过get()方法获得对象,但是虚引用不行。虚引用的get方法形同虚设,总是返回null。虚引用在任何时候都可能被GC,不能单独使用,必须配合引用队列(ReferenceQueue)来使用。设置虚引用的唯一目的,就是在这个对象被回收时,收到一个通知以便进行后续操作,有点像Spring的后置通知。

换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用 finalize方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。详见PhantomReferenceDemo

引用队列

弱引用、虚引用被回收后,会被放到引用队列里面,通过poll方法可以得到。关于引用队列和弱、虚引用的配合使用,见ReferenceQueueDemo

强、软、弱、虚引用小结:


参考:https://github.com/MaJesTySA/JVM-JUC-Core/blob/master/docs/JVM.md

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容

  • Java 虚拟机有自己完善的硬件架构, 如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM 屏蔽了与具体操作系...
    尹小凯阅读 1,685评论 0 10
  • 转载blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile阅读 5,358评论 1 56
  • 内存溢出和内存泄漏的区别 内存溢出:out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,...
    Aimerwhy阅读 734评论 0 1
  • 介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明 程序计数器:看做当前线程所执行的字节码行号指示器...
    jemmm阅读 2,227评论 0 9
  • 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参...
    吃番茄的土拨鼠阅读 608评论 1 0