JVM概述
JVM 是一种用于计算机设备的规范,它是一个虚构的计算机的软件实现,简单的说,JVM 是运行 byte code 字节码程序的一个容器。
它有一个解释器组件,可以实现 JAVA 字节码和计算机操作系统之间的通信,java程序只需要在JVM 上一次编译,多出运行,因此JAVA具有跨平台性。
内存结构
- 方法区(常量池、静态变量、构造函数、类数据)
堆(对象、类实例、GC的主要区域)
新生区(Minor GC 、Full GC清理无用数据)
* 伊甸园(对象创建) * 幸存 0 区 * 幸存 1 区
- 老年代(对象的声明周期到老年代结束)(Full GC)
- 永久区(jdk 1.8 以后被元空间代替)(Major GC)
- 程序计数器(记录每个运行线程的内存地址)
- 虚拟机栈(每个方法创建都会创建一个栈,栈内的数据都是临时的)
- 本地方法栈
- 直接内存
堆中的 GC 回收过程
对象会在 Eden(伊甸园)分配创建,当 Eden(伊甸园)没有足够空间时将发起一次 Minor GC(垃圾清理),当 Eden 执行 Minor GC 后还不足以为对象分配空间,则大的对象直接进入老年代,可以用参数设置大对象直接进入老年代,避免频繁 Minor GC 。如果对象在 Eden 创建,发生 Minor GC 后仍然存活,且能被 Survivor 幸存去容纳,年龄加 1, 达到一定年龄进入老年代,默认为 15。发生 Mrinor GC之前先检查老年代最大可用连续空间是否大于新生代所有对象总空间,如果大于,说明 Minor GC 安全;否则会判断是否被担保失败,如果担保失败了,判断老年代最大连续空间是否大于历次晋升到老年代对象的平均大小,如果大于则尝试 Minor GC ,否则就执行 Full GC 进行对象回收,如果 Full GC 执行完毕后,对象仍然无法被创建,则直接抛出内存溢出的异常(java.lang.OutOfMemoryError)。
如何改变对象对象进入老年代的最大值?
通过修改-XX:PretenureSizeThreshold参数来设置进入老年代的对象年龄。这样也避免在 Eden(伊甸园)区和两个 Survivor 之间发生大量的内存复制。(默认值为 15)
GC如何判断对象是否改被回收
垃圾收集的算法
都有那些垃圾回收器
内存泄漏(不再使用的对象的内存不能被GC回收)
内存泄漏的例子:
单例模式:
不正确使用单例模式是引起内存泄漏的一个常见问题,单例对象在初始化后将在JVM的整个生命周期中存在(以静态变量的方式)。如果单例对象持有外部的引用,那么这个对象将不能被JVM正常回收,导致内存泄漏。所以需要注意,尽量不要在单例中持有大对象。
各种连接:
比如数据库连接、socket连接、文件流等,除非其显式的调用其close()方法将连接关闭,否则是不会自动被垃圾 回收的。
静态集合类:
我们循环申请Object对象,并将所申请的对象放入一个Vector中。如果我们仅仅释放引用本身,那么Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。
如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。
Static Vector v = new Vector(10); for (int i = 0; i < 100; i++) { Object o = new Object(); v.add(o); o = null; }
事件监听器:
AWT的事件处理机制是一种委派式事件处理方式:普通组件(事件源)将整个事件处理委托给特定的对象(事件监听器);当该事件源发生指定的事件时,就通知所委托的事件监听器,由事件监听器来处理这个事件。
比如常用的监听器有ActionListener、KeyListener、MouseListener、MouseMotionListener(专门处理鼠标运动事件的,比如鼠标的移动和拖动)
如果在释放对象的时候没有记得删除这些监听器,会增加内存泄露的机会。
import java.awt.*; import java.awt.event.*; public class TestButton { public static void main(String args[]) { Frame f = new Frame("Test"); Button b = new Button("Press Me!"); b.addActionListener(new ButtonHandler()); /*注册事件监听器*/ f.setLayout(new FlowLayout()); //设置布局管理器 f.add(b); f.setSize(200,100); f.setVisible(true); } } //实现接口ActionListener才能做事件ActionEvent的处理者 class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e) { System.out.println("Action occurred"); } }
调优
JVM 思维导图
最后
这些JVM篇章已经全部整理成一套完整且体系的pdf文档,无论是思维脑图、学习笔记还是面试考点全整理好了,实际内容还有很多,就不一一展示,若你也需要这一套学习资料。
关注我的公众号:前程有光即可领取
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。