定义
Java Virtual Machine -java程序的运行环境
好处:
- 一次编写,到处运行
- 自动内存管理,垃圾回收功能
- 数组下标越界 越界检查
- 多态
比较:
jvm jre jdk
构成:
1.程序计数器
定义
Program counter register程序计数器(寄存器)
jvm中的组件解释器将虚拟机指令翻译成机器码,提供给cpu执行
- 作用:记住下一条jvm指令
- 特点:
1. 线程私有
2. 不会存在内存溢出
2.栈
Java Virtual Machine Stacks(Java虚拟机栈)
- 每个线程运行所需要的内存,成为虚拟机栈
- 每个栈由多个栈帧frame组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
垃圾回收不涉及栈内存回收
方法内的局部变量是否线程安全
- 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
- 如果是局部变量引用了对象,并逃离方法的作用方法,需要考虑线程安全
-Xss 设置线程栈空间
栈内存溢出
- 栈帧过导致栈内存溢出
- 栈帧过多导致内存溢出
运行诊断:
- 用top定位哪个进程对cpu的占用过高
- ps H -eo pid,tid,%cpu | grep进程id (用ps命令进一步定位是哪个线程引起的cpu占用过高
- jstack 进程id: 可以根据线程id找到有问题的线程,进一步定位到问题代码的源码行号
3.堆
Heap堆,通过new关键字,创建对象都会使用堆内存
特点:
- 线程共享,堆中对象都需要考虑线程安全的问题
- 有垃圾回收机制
内存诊断
- jps工具 查看当前系统中有那些java进程
- jmap工具: 查看堆内存占用情况
- jconsole工具 图形界面的,多功能的检测工具,可以连续监测
- jvisualvm 可视化虚拟机
4.方法区
5.运行时常量池
对于class文件 javap -v HelloWord.class 反编译class文件
类基本信息,常量池,类方法定义,包含了虚拟机指令
- 常量池:就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
- 运行时常量池:常量池是*.class文件中的,当该类被加载,它的常量池信息就会被放入运行时常量池(运行时放入内存中),把里面的符号地址变为真实地址
StringTable串池 hashTable结构 不能扩容
1.常量池中的信息,都回被加载到运行时常量池,这是a b ab都是常量池中的符号,还没有变为java字符串对象
2.ldc #2回把 a符号变为“a"字符串对象(先去stringTable中找,没找到则放入string table
打印false,true,s3在串池中而s4在堆中,s5编译期间结果已确认,直接记录为ab,发现串池中有了
打印结果true,true,因为一开始串池中没有,所以直接将s放入了串池,所有s==”ab“
若第一行直接有一个String x = ”ab“,在后面有这个s则串池中已经有了不会放入,则s != “ab”
5.1 StringTable特性
- 常量池中的字符串仅是符号,第一次用到时才变为对象
- 利用串池的机制,来避免重复创建字符串对象
- 字符串变量拼接的原理时StringBuilder(1.8)
- 字符串变量拼接的原理时编译器优化
- 可以使用intern方法,主动将串池中还没有的字符串对象放入串池
- 1.8将这个字符串对象尝试放入串池,如果有则并不会放入,没有则放入并将串池中的对象返回
- 1.6将这个字符串对象尝试放入串池,如果有则并不会放入,没有则复制一份放入并将串池中的对象返回 此时池两个对象
5.2 StringTable性能调优
调整:-XX:StringTableSize=桶个数 适当调大减少哈希碰撞提升性能
大量字符串时可以先inter()
6 直接内存
Direct mEMORY
- 常用于NIO操作,用于数据缓冲区
- 分配回收成本较高,但读写性能高
- 不受JVM内存回收管理
ByteBuffer.allocateDirect(); - 使用了Unsafe对象完成直接内存的分配回收,并且回收需要主动调用freeMemory方法
- ByteBuffer的实现类内部,使用了Cleaner(虚引用)来检测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过Cleaner的clean方法调用freeMemory来释放直接内存