JVM学习-Java内存处理

时间:2021-02-24 19:24:36

Java堆内存异常:

内存异常分为内存泄漏和内存溢出。

内存泄漏:leak,☞创建的对象不需要了,永远也用不到了,但是一直有引用指向这个对象,让其一直无法被垃圾回收,而且增大堆内存无法解决的异常。

内存溢出:对象还需要,但是内存不够了,出现这种问题,可以通过增大内存来解决。(或者缩短对象存活时间)

虚拟机栈的内存异常:

*Error:只会发生于单线程环境下。指当前线程请求的栈深度大于虚拟机的栈深度。

OutOfMemery:没有足够的内存支持栈扩展,就会产生OOM,主要发生在多线程。

解决方法:减小堆内存大小,减小栈内存大小(换取更多线程的创建)。

一下是虚拟机的配置命令:

 JVM参数设置

JVM学习-Java内存处理

-Xss128k:设置栈大小为128k

-XX:+PrintGCDetails :打印GC日志

-XX:+UseSerialGC : 设置GC为SerialGC

-Xms20M : 设置堆的最小大小为20M

-Xmx20M : 设置 堆的最大大小

-Xmn10M :设置新生带大小

-XX:PretenureSizeThreshold=3145728(字节为单位)大于3M的直接进入老年代

Java的垃圾回收器和内存分配策略:

垃圾回收的主要对象就是我们创建的对象。

回收对象的前提是对象已经死了。

如何判断对象死了?

方法1:引用计数法,给每个对象添加一个引用计数器,每当有一个地方引用这个对象时,计数器 + 1,每当有一个引用失效时,计数器 - 1,任何时候这个对象的引用数为0时,就可以判断这个对象死了。

优点:实现简单,判定效率较高,Python使用这个方法。

缺点:无法解决对象的循环引用问题,所以java没有采用。

方法2:可达性分析算法,通过判断到GCRoots是否可达来判断对象是否该死(Java采用)

一般一下几种可作为GCRoots。

  1. 虚拟机栈帧中局部变量表中引用的对象。
  2. 本地方法中引用的对象。
  3. 方法区中静态属性引用的对象。
  4. 方法区中常量引用的对象。

引用的分类:

强引用(Strong Refference):Object o = new Object(),强引用存在永远不会被回收。

软引用(Soft Refference):此引用指向的对象有用,但是不是必须的,可以下次进来再创建。如果要发生内存溢出时,就会将软引用对象列入回收范围内。进行二次回收,如果内存还是不够,就会抛出OOM。

弱引用(Weak Refference):非必须对象,最多存活到下次垃圾回收之前。

虚引用(Fantom Refference):幽灵引用,不对对象的生存时间造成影响,也无法通过虚引用来取得一个对象实例,使用虚引用的唯一目的是在这个对象被垃圾回收之前收到一个系统通知(可以知道对象是啥时候死的)。

对象的自我拯救:

任何一个对象的finalize方法都只会被JVM调用一次,判断一个对象是否死亡要经过两个阶段,和两次标记,

第一阶段:缓刑阶段(到GCRoots不可达),第一次标记,标记的时候会查看这个对象是否覆写finalize方法。没覆盖直接死,如果覆盖了,就判断这个finalize方法是否被执行过,如果被执行过了,代表这个对象死了,就给他标记个死字,下次GC直接回收,如果在finalize中,这个对象和任何一个GCRoots相连了,则这个就自我拯救成功了,每个对象只能自我拯救一次。