JVM第三天

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34629467/article/details/79492002

首先贴上第二天学习的相关笔记:

trace
-verbose: gc
-XX: +printGC
可以打印GC的简要信息:
回收了4M的空间
[GC 4790K->374K(15872K),0.0001606 secs]
-XX:+PrintGCDetails
-打印GC详细信息
-XX:+PrintGCTimeStamps
-打印GC发生的时间戳
例:
[GC[DefNew:4416K->0K(4928K),0.0001897 secs]4790K->374K(15872K),0.0002232 secs]
[Times: user=0.00, sys=0.00, real=0.00 secs]
-XX:+PrintGCDetails的输出
-Heap
-def new generation 新生代: 总共可以使用,已使用,剩余可用使用 (低边界,当前边界(申请到的位置),最高边界(最多申请的位置))

-eden space : 伊甸园, 总共可以使用,已使用,剩余可用使用
-from space : 
-to space : 
新生代的空间大小 = 伊甸园 + from space + to space
-tenured generation : 老年代 
-the space
-compacting perm gen  : 持久代: 总共可以使用,已使用,剩余可用使用
-the space
-ro space : 共享空间
-rw space : 
-Xloggc: log/gc.log
-指定GC log 的位置,以文件输出
-帮助开发人员分析问题
-XX:+PrintHeapAtGC
-每一次GC后,都打印堆信息:
GC调用前: 显示新生代的使用信息,伊甸园的使用信息,年老代的使用信息;
GC后: 新生代被释放很多,有部分新生代迁移到了年老代
-XX:+TraceClassLoading
-监控类的加载
Loaded java.lang.Object
Loaded java.io.Serializable
-XX:+PrintClassHistogram
-按下Ctrl + Break 后,打印类的信息:
num #instances #bytes class name

-分别显示: 序号、实例数量、总大小、类型


堆的分配参数
-Xmx -Xms
-指定最大堆和最小堆
- -Xmx20m  -Xms5m 运行代码:

-java会尽可能维持在最小堆,当无法维持的时候,jvm会进行扩容!

Xmx和Xms应该保持一个什么关系呢,可以让系统的性能尽可能的好呢

如果你要做一个Java的桌面产品,需要绑定jre,但是jre又很大,你如何做一下jre的瘦身呢

-Xmn:设置绝对值大小
-设置新生代大小
-XX:NewRatio
-新生代(eden + 2 * s)和年老代(不包含永久区)的比值
-4 表示新生代:年老代 = 1 : 4即年轻代占堆的1/5
-XX: SurvivorRatio : 幸存区: from space to space
-设置两个Survivor区和eden的比
-8表示两个Survivor : eden = 2 : 8,就是一个Survivor占年轻代的 1/10

byte[] b = null;
for(int i = 0; i < 10; i++){
b = new byte[1024*1024];//分配10M空间

}
-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails
最大堆 最小堆 新生代分配 1m  打印GC详细信息

1:没有触发GC
2:全部分配在老年代

-Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails
最大堆 最小堆 新生代分配 15m  打印GC详细信息
1:没有触发GC
2:全部分配在eden
3:老年代没有使用

-Xmx20m -Xms20m -Xmn7m -XX:+PrintGCDetails
最大堆 最小堆 新生代分配 1m  打印GC详细信息

1:进行了2次新生代GC
2: s0 s1太小需要老年代担保

-Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails
1:进行了3次新生代GC
2:s0 s1 增大

首先定义新生代空间大小

-XX:+HeapDumpOnOutOfMemoryError
-OOM时导出堆到文件
-XX: +HeapDumpPath
-导出OOM的路径
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

-XX:OnOutOfMemoryError
-在OOM时,执行一个脚本
-"-XX:OnOutOfMemoryError=D:/tools/jdks/bin/printstack.bat %p"
*根据实际事情调整新生代和幸村代的大小
*官方推荐新生代占堆的3/8
*幸村代占新生代的1/10
*在OOM时,记得DUMP出堆,确保可以排查现场问题

永久区参数分配:
-XX:PermSize -XX:MaxPermSize
-设置永久区的初始化空间和最大空间
-他们表示,一个系统可以容纳多少个类型

使用CGLIB时,可能会产生大量的类,这些类就是占用永久代的空间,有可能撑爆永久区,导致OOM

新生代:
伊甸区
from space to space 是 Survivor区

年老代:

持久代:

打开堆的Dump
-堆空间实际占用非常少
-但是永久区溢出,一样抛出OOM
如果堆空间没有用完也抛出了OOM,有可能是永久区导致的!

栈的分配参数
-Xss
通常只有几百K
决定了函数调用的深度
每个线程都有独立的栈空间
局部变量、参数分配在栈上
总栈空间大小 = 线程数 * 每个线程分配的空间
如果想要多跑线程,那么应该使用较小的栈空间分配!
就是增大栈空间,那么容纳的线程数量就是减少的!
栈溢出==》一般是函数调用层次太深!!!

局部变量表,局部变量

然后是第三天关于GC算法以及种类的学习:

GC算法与种类
GC的概念
引用计数法
标记清除法
标记压缩法
复制算法
可触及性
Stop-The-World


①垃圾收集器: 
无用的对象仍占据空间,我们希望在一定时间能回收。
后台线程: 守护线程GC算法进行垃圾回收。
②GC的对象是 堆空间和永久区(PermGen: )
新生代
年老代
永久区


老牌垃圾回收算法
通过引用计算来回收垃圾
使用者:
-Com
-ActionScript3
-Python
通过引用计数器来进行的;
对于一个对象A,只要有任何一个对象引用了A,引用计算器就加1;引用对象消失,引用计数器就减1;
问题:
-引用和去引用伴随加法和减法,影响性能
-很难处理循环引用
垃圾对象的循环引用的引用计数器是没法释放的,多次累计导致内存递增



标记-清除法:
①标记阶段:
在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。
因此,未被标记的对象就是未被引用的垃圾对象。
然后,在清除阶段,清除所有未被标记的对象。

从根节点,可以到达的存活对象就进行标记。
空白区域为空闲空间;
黑色区域为垃圾对象;

清除阶段: 将未进行标记的对象进行空白化就完成了清除。

②清除阶段:

标记-压缩:
①标记压缩算法适用于存活对象较多的场合,如老年代,它在标记清除算法的基础上做了一些优化,
和标记-清除算法一样,标记压缩算法也首先需要从根节点开始,对所有可达对象做一次标记;
但是之后,它并不清理未标记的对象,而是将所有的存活对象压缩到内存的一端。
之后,清理边界外所有的空间。

标记压缩有什么优势呢?
如何判断存活对象的多少呢?


复制算法:
①与标记-清除算法相比,复制算法是一种相对高效的回收方法
②不适合于存活对象较多的场合 如年老代
③将原有的内存空间分为两块,每次只使用其中的一块,在垃圾回收时,将正在使用的
内存中的存活对象复制到未使用的内存块中,之后清除正在使用的内存块中的所有对象,
交换两个内存的角色,完成垃圾回收。
复制算法的最大问题: 空间浪费 整合标记清理思想;

复制空间一般会很少,因为复制空间越大,浪费空间越大!

大对象一般放在老年代!

复制空间需要担保空间,就是老年代!长期有用的对象也放在老年代!接着就是年轻的对象复制到另一个相同大小的空间!

eden区
from space  to space 这两个空间完全一样!
复制算法一定会浪费部分空间!


分代思想:
依据对象的存活周期进行分类,短命对象归为新生代,长命对象归为老年代!
根据不同的特点,选取合适的算法:
-少量对象存活,适合复制算法
-大量对象存活,适合标记清理或者标记压缩

总结:
引用计数:
-没有被java采用
标记-清除
标记-压缩
复制算法
-新生代明确使用的一种算法


------需要识别一个垃圾对象,因此需要给出一个可触及性的定义:
*可触及性的
-从根节点可以触及到这个对象

避免使用finalize,操作不慎可能导致错误
优先级低,何时被调用,不确定
何时发生GC不确定
可以使用try-catch-finally(在finally里面去释放资源比较好)来替代它
***根
-栈中引用的对象
-方法区中静态成员或者常量引用的对象(全局对象)
-JNI方法栈中引用对象

*可存活的
-一旦所有引用被释放,就是可复活状态
-因为在finalize()中可能复活该对象
*不可触及的
-在finalize()后,可能进入不可触及状态
-不可触及的对象不可能复活
-可以回收



Stop-the-world
-java中一种全局暂停的现象
-native代码可以执行,但不能和JVM交互,全局暂停,java代码停止
-多半由GC引起
*DUMP线程
*死锁监察
*堆DUMP

GC时为什么会全局停顿?
-想要垃圾干净,至少要在某一个状态下,垃圾要被完全清理。
GC线程回收垃圾时,产生一个所有的线程停止一下,保证没有新的垃圾产生,以便好的标记回收垃圾。
minorGC停顿时间很短,一般没有什么影响
majorGC停顿时间有时会比较长,
危害?
-长时间服务停止,没有响应
-遇到HA系统,可能引起主备切换,严重危害生产环境。


----------分析配图省略,仅为记录个人学习笔记------------------


----------实战心得个人会适时地分享----------------













































































展开阅读全文

没有更多推荐了,返回首页