- JVM运行时的数据区
- 堆:存放几乎所有的对象实例和数组,有GC管理,线程共享,会抛出OOM异常;堆中可能会为各个线程分配一定的内存空间,作为TLS\TLAB缓存;jdk8将字符串常量池放入到堆中
- 方法区(非堆):存放已经被JVM加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存,线程共享;运行时常量池是方法区的一部分,是一块内存区域,Class 文件常量池将在类加载后进入方法区的运行时常量池中存放
- 虚拟机栈:每个线程一个栈(主线程也是一个线程),可能抛OOM和SO异常,存储:
-- 局部变量表:8种基本类型、引用类型、returnAddress类型
-- 操作数栈:各种操作数指令
-- 动态连接:每个栈帧中包含一个在常量池中对当前方法的引用,目的是支持方法调用过程中的动态连接
-- 方法出口:正常退出或者异常退出 - PC(程序计数器寄存器):保证CPU时间片切换线程时,恢复现场
- 本地方法栈:执行Native方法服务
- 本地内存/直接内存
- 不是JVM的一部分,使用NIO类的Native函数库直接分配堆外内存
- 动态扩展也可能出现OOM异常
- 元空间是本地内存,常量、类元信息klass、字段、静态成员、方法等
3.内存泄漏
- 内存泄漏发生在堆中,当对象不再使用时,GC收集器却无法回收,认为这些对象还处于引用阶段
- 以下几种情况可能导致内存泄漏:
-- 大量使用static对象
-- 资源没有及时释放,如数据库连接、输入输出流,JVM都会为这些资源分配内存
-- 不正确覆写equals和hashCode方法,在HashMap和HashSet更新key成员、删除、添加等操作可能会造成内存泄漏、
-- 引用了外部类的内部类
-- 使用ThreadLocal造成内存泄露,使用线程池时,线程池有线程重用的功能,ThreadLocal没有显式的删除时,就会一直保留在内存中,不用的时候需要调用remove方法
- 有关JVM、进程、线程的关系
- 启动一个JAVA程序、即启动一个JVM就是一个进程;
- 除了启动主线程之外,还会启动以下几个线程:
-- Reference Handler 处理引用的线程
-- Finalizer 调用对象的finalize方法的线程,就是垃圾回收的线程
-- Signal Dispatcher 分发处理发送给JVM信号的线程
-- Attach Listener 负责接收外部的命令的线程
-- Monitor Ctrl-Break