为了解决引用计数法的循环引用问题,Java 使用了可达性算法。
跟踪收集器采用的为集中式的管理方式,全局记录对象之间的引用状态,执行时从一些列GC Roots的对象做为起点,从这些节点向下开始进行搜索所有的引用链,当一个对象到GC Roots 没有任何引用链时,则证明此对象是不可用的。
图中,对象Object6、Object7、Object8虽然互相引用,但他们的GC Roots是不可到达的,所以它们将会被判定为是可回收的对象。
哪些对象可以作为 GC Roots 的对象:
XX 参数
jinfo 举例,如何查看当前运行程序的配置
1
|
public class HelloGC {
|
我们可以使用 jps -l
命令,查出进程 id
1
|
1923 org.jetbrains.jps.cmdline.Launcher
|
在使用 jinfo -flag PrintGCDetails 1933
命令查看
1
|
-XX:-PrintGCDetails
|
可以看出默认是不打印 GC 收集细节
也可是使用jinfo -flags 1933
查看所以的参数
查看初始默认值:-XX:+PrintFlagsInitial
1
|
cuzz@cuzz-pc:~/Project/demo$ java -XX:+PrintFlagsInitial
|
查看修改更新:-XX:+PrintFlagsFinal
1
|
bool UsePSAdaptiveSurvivorSizePolicy = true {product}
|
= 与 := 的区别是,一个是默认,一个是人物改变或者 jvm 加载时改变的参数
1
|
cuzz@cuzz-pc:~/Project/demo$ java -XX:+PrintCommandLineFlags
|
-XX:+PrintGCDetails
输出详细 GC 收集日志信息
代码
1
|
public class HelloGC {
|
打印结果
1
|
[GC (Allocation Failure) [PSYoungGen: 1231K->448K(2560K)] 1231K->456K(9728K), 0.0015616 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
|
在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用;Java中根据其生命周期的长短,将引用分为4类。
软引用
代码验证
我设置 JVM 参数为 -Xms10m -Xmx10m -XX:+PrintGCDetails
1
|
public class SoftReferenceDemo {
|
输出
1
|
[GC (Allocation Failure) [PSYoungGen: 1234K->448K(2560K)] 1234K->456K(9728K), 0.0016748 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
|
发现当内存不够的时候就会被回收。
弱引用
代码验证
1
|
public class WeakReferenceDemo {
|
输出
1
|
java.lang.Object@1540e19d
|
值得注意的是String name = "cuzz"
这种会放入永久代,以及 Integer age = 1
在 int 中 -128 到 127 会被缓存,所以是强引用,然后 GC 也不会被回收。
引用队列
1
|
public class ReferenceQueueDemo {
|
输出
1
|
java.lang.Object@1540e19d
|
会把该对象的包装类即weakReference
放入到ReferenceQueue
里面,我们可以从queue中获取到相应的对象信息,同时进行额外的处理。比如反向操作,数据清理等。
java.lang.OutOfMemoryError : Direct buffer memory
配置参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
1
|
public class DirectBufferDemo {
|
输出
1
|
maxDirectMemory : 5MB
|
java.lang.OutOfMemoryError : unable to create new native thread
具体的实现可以看看这个帖子:几种手动OOM的方式
底层原理
Region 区域化垃圾收集器:最大好处是化整为零,避免全内存扫描,只需要按照区域来进行扫描即可。
G1的内存结构和传统的内存空间划分有比较的不同。G1将内存划分成了多个大小相等的Region(默认是512K),Region逻辑上连续,物理内存地址不连续。同时每个Region被标记成E、S、O、H,分别表示Eden、Survivor、Old、Humongous。其中E、S属于年轻代,O与H属于老年代。
H表示Humongous。从字面上就可以理解表示大的对象(下面简称H对象)。当分配的对象大于等于Region大小的一半的时候就会被认为是巨型对象。H对象默认分配在老年代,可以防止GC的时候大对象的内存拷贝。通过如果发现堆内存容不下H对象的时候,会触发一次GC操作。
原文:https://www.cnblogs.com/wgy-01/p/12033363.html