JVM
java虚拟机,java程序的运行环境(java二进制字节码的运行环境),屏蔽java代码与底层操作系统之间的差异
优点
-
一次编写,到处运行
-
自动内存的管理,垃圾回收功能
-
数组下标越界检查
-
多态是面向对象编程的基础,jvm如何实现多态?
JVM、JRE、JDK
jvm
jre=jvm+基础类库
jdk=jvm+基础类库+编译工具
java源代码->二进制字节码 jvm指令->执行引擎的解释器->机器码->交给cpu运行
二进制字节码(类基本信息,常量池,类方法定义,包含了虚拟机指令)。常量池就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息。
JVM内存结构
方法区:存放和类相关的信息,在虚拟机启动时,方法区也会导致内存溢出
-
1.8以前永久代实现,类、类加载器、运行时常量池,由jvm管理内存结构
-
1.8以后元空间实现,移到本地内存中进行管理(操作系统内存,stringtable从常量池移到了堆heap中
-
运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会被放入运行时常量池,并把里面的符号地址变为真实地址
堆:放对象
-
通过new关键字,创建对象都会使用堆内存
-
特点
-
线程共享的,堆中对象都需要考虑线程安全的问题
-
有垃圾回收机制,堆中不被使用的对象就会被回收
-
-
堆内存诊断
-
jps工具,查看当前系统中有哪些java进程
-
jmap工具,查看某一个时刻 某个进程堆内存占用情况
-
jconsole工具,图形界面的,多功能的监测工具,可以连续监测
-
-
垃圾回收后,内存占用依然。jvisualvm可以查看哪个对象占用的内存过高
虚拟机栈
-
每个线程运行时所需要的内存,称为虚拟机栈
-
每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存(参数、局部变量、返回地址)
-
每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
-
垃圾回收只是回收堆内存中的无用对象,不涉及栈内存
-
栈内存不是越大越好,栈内存越大,线程数会变小,因为物理内存是有限的
-
方法内的局部变量是否线程安全?如果是共享变量如static int x=0,需要考虑线程安全;如果是线程私有的变量,则不需要考虑线程安全的问题
-
如果方法内部局部变量没有逃离方法的作用范围,是线程安全的
-
如果是局部变量引用了对象,并逃离了方法的作用范围,需要考虑线程安全
-
-
栈内存溢出
-
栈帧过多导致栈内存溢出StackOverflowError,例如递归没有合适的结束条件
-
栈帧过导致栈内存溢出
-
-
线程运行诊断
-
cpu占用过多
-
用top定位哪个进程对cpu的占用过高
-
ps H -eo pid,tid,%cpu | grep 进程id(用ps命令进一步定位是哪个线程引起的cpu占用过)
-
jstack 进程id,可以根据线程id找到有问题的线程,进一步定位到问题代码的源码行号
-
-
程序运行很长时间没有结果
-
程序计数器
-
作用:记住下一条jvm指令的执行地址,物理上通过寄存器实现
-
特点
-
线程私有的
-
不会存在内存溢出
-