架构师训练营 - 第⑨周总结
JVM组成架构
类加载器(双亲委托模型,从下到上依次询问是否已加载,从上到下依次尝试是否可加载)
BootstrapLoader
PlatformLoader
Application ClassLoader
自定义类加载器:(隔离加载类、扩展加载源、字节码加密)
运行期数据区
方法区:存放磁盘加载的类字节码,静态变量、常量等。
堆:每个jvm对应唯一一个堆,所有类实例和数组对象都放在堆,并在所有线程中共享
java栈:每个线程一个栈、存放基本类型变量和对象引用
程序计数寄存器:记录当前线程执行到哪一行字节码指令
执行引擎
跨平台运行
Java字节码文件:统计格式
虚拟机:将字节码文件转换为当前平台的机器码
字节码执行流程:方法计数器达到一定次数时编译为机器码执行,否则解释执行
多线程与线程安全
线程工作内存:多线程情况下,线程操作主内存变量需要通过线程独有的工作内存拷贝变量副本来进行
Volatile:保证不同线程操作的可见性、禁止进行指令重排序
JVM垃圾回收:将堆中不再使用的对象清理掉,释放内存空间
如何知道哪些对象需要回收-标记:
可达性分析算法:从栈帧的局部变量或者方法区的静态变量出发,将这些变量应用的对象进行标记,然后看这些对象是否引用了其他对象,继续标记。
没有标记过的对象就是可回收的垃圾对象
如何回收:
清理:将垃圾对象占用的空间标记为空闲,记录在一个空闲列表,建立新对象时就从其中找一段空闲内存分配给这个新对象
压缩:从堆空间头部开始,将存活的对象拷贝到一段连续的空间,其余的空间就是连续的空闲空间
复制:将堆空间分成两部分,一部分创建对象,当这个部分空间满了就将标记过的对象复制到另一个空间
回收过程中内存空间如何管理
分代回收
新生代(Eden、From、To)
老年代
用什么样的过程回收-垃圾回收算法
串行回收
并行回收
并行回收CMS
G1
JVM性能诊断工具
JPS:进程查看
JSTAT:资源和性能监控,包括对堆大小和垃圾回收状况的监控
JMAP:输出内存中所有对象的工具
JSTACK:查看线程堆栈信息
Jconsole、JVisualVM集成工具
合理并慎用使用多线程:
使用场景(I/O阻塞、多CPU并发)
资源争用与同步问题
java.util.concurrent
启动线程数=【任务执行时间/(任务执行时间-IO时间)】* cpu内核数
同一个程序中运行的多个线程本身没有问题,问题在于多个线程访问了相同的资源,当两个线程同时访问同一个资源时,如果对资源访问的顺序敏感,就存在竞态条件。导致竞态条件存在的代码称作临界区。
Java线程安全
允许多个线程并发的执行的代码成为线程安全的代码
局部变量:存储在线程自己的栈,永远不会被共享
局部对象:对象不会逃逸出方法就是安全的
对象成员:对象存储在堆上,如果运行两个线程同时更新同一个对象的同一成员,就是线程非安全的
ThreadLocal:共享线程内数据,注意清空数据
Java内存泄漏:永久保留不再使用的对象引用导致垃圾无法回收
合理使用线程池和对象池
复用对象或线程资源,避免在程序的声明周期中大量创建或删除
对象内容清楚(ThreadLocal)
使用适合的JDK容器类(List、Map、concurrent包)
缩短对象生命周期,加速垃圾回收
减少对象驻留内存时间
在使用时创建对象,使用完释放
创建对象的步骤(静态代码->静态变量->父类构造函数->子类构造函数)
任何计算机问题都可以通过中间层(虚拟层)解决
评论