前言
大多数情况下无须对内存的分配、释放做太多考虑,对JVM也无须有多么深的理解。但写程序过程中也往往因为这样的原因那样的原因,造成很多不易察觉的内存问题。当内存问题出现的时候,也不能很快的定位并解决问题。
java程序,最终会编译成字节码运行在JVM上:
- hotSpot
- jRockit
- J9
- Dalvik
- ART
JVM虚拟机内存 (java 7)
内存组成、内存分配过程、对象访问几个方面
java 运行时内存区
方法区、堆、程序计数器、虚拟机栈、本地方法栈
线程私有: 1.程序计数器 :字节码行号 2.java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧,存储局部变量表、操作栈、动态链接、方法出口等。 3.本地方法栈
线程共享: java 堆: 方法区: 直接内存
内存分配过程
对象访问
内存溢出
- 线程请求的栈深度大于虚拟机所允许的最大深度,如递归调用OOM
- 虚拟机在扩展栈时无法申请到足够的内存,不停的创建线程触发OOM
- 创建大量对象并且对象生命周期都很长的情况
- 方法区存放Class等元数据信息,如产生大量类(CGLIB)
垃圾回收理论
java内存管理就是为了应对网站/服务访问慢的问题:
- 内存:垃圾回收占用CPU;存入太多的数据,造成内存泄漏
- 线程死锁
- I/O速度太慢
- 依赖的其他服务相应太慢
- 复杂的业务逻辑或者算法造成响应的缓慢
垃圾回收对性能的影响一般有以下几个:
- 内存泄漏
- 程序暂停
- 程序吞吐量显著下降
- 响应时间变慢
垃圾回收的一些概念
- 回收的同时可运行其他的工作进程
- 使用多CPU进行垃圾回收
- 回收时必须暂停其他所有的工作
- 使用引用计数算法的GC,出现对象的计数器溢出,则起不到标记某个是垃圾的作用
- 变异
- 引用计数垃圾回收
- 标记-清理(对象分代)
GC流程和算法
GC的一般流程:
- 找出堆中活着的对象
- 释放死对象占用的资源
- 定期调整活对象的位置
找出活着的对象和释放死对象的情况可以使用以下算法:
- 标记-清除
- 标记-整理
- 复制算法
- 标记 Mark
- 清除 Sweep
- 压缩 Compact
- 复制 Copy