(黑马jvm视频笔记)
前言
内存结构
一、程序计数器
1.定义
Program Counter Register 程序计数器(寄存器)
作用: 是记录下一条 jvm 指令的执行地址行号
图解:
java源码经过编译后生成二进制字节码文件,二进制字节码文件为jvm指令。程序运行时0被提交到解释器,同时3的地址被存入程序计数器,解释器将0翻译为机器码后交给cpu执行,执行完成后解释器直接去程序计数器中获取到3的地址,重复上一次的流程。
特点:
(1)是线程私有的
(2)不会存在内存溢
二、虚拟机栈
1.定义
(1)每个线程运行需要的内存空间,称为虚拟机栈
(2)每个栈由多个栈帧组成,对应着每次调用方法时所占用的内存(包含方法的参数,局部变量以及返回地址)
(3)每个线程只能有一个活动栈帧,即这个线程正在执行的方法
示例代码:
public class Main {
public static void main(String[] args) {
method1();
}
private static void method1() {
method2(1, 2);
}
private static int method2(int a, int b) {
int c = a + b;
return c;
}
}
2.栈内存的配置
-Xss size:定义线程的栈内存大小
不配置时的默认大小:
Linux/x64(64-bit): 1024KB
macOS(64-bit): 1024KB
Oracle Solaris/x64(64-bit): 1024KB
Windows: 默认值取决于虚拟内存
3.问题辨析
(1)垃圾回收是否涉及栈内存?
不涉及。因为栈内存是一次次方法调用产生的栈帧内存,栈帧在方法执行完毕之后会被弹出栈,自动被回收掉,不需通过垃圾回收机制去回收内存。
(2)栈内存的分配越大越好吗?
不是。因为物理内存是一定的,栈内存越大,可以支持更多的递归调用,但是可执行的线程数就会越少。
(3)方法内的局部变量是否是线程安全的?
如果方法内局部变量没有逃离方法的作用范围,则是线程安全的
如果如果局部变量引用了对象,并逃离了方法的作用范围,则需要考虑线程安全问题
例子:
4.栈内存溢出
(1)报错提示
Java.lang.stackOverflowError 栈内存溢出
(2)发生原因
虚拟机栈中,栈帧过多(无限递归)
每个栈帧所占用过大(少数情况)
5.线程运行诊断
CPU占用过高
Linux环境下运行某些程序的时候,可能导致CPU的占用过高,这时需要定位占用CPU过高的线程
top命令,查看是哪个进程占用CPU过高
ps H -eo pid,tid,%cpu | grep pid,通过ps命令进一步查看是哪个线程占用CPU过高
jstack pid 查看进程中的线程信息
其中进程中的线程的nid与上一步中tid的16进制相等,可以将tid转换为16进制来和nid进行对比
三.本地方法栈
本地方法是指java中带有native关键字的方法需要java去调用本地的C或者C++方法,因此java需要给本地方法提供内存空间,称之为本地方法栈
四.堆
1.定义
Heap堆
通过new关键字创建的对象都会被放在堆内存
特点
(1)所有线程共享,堆内存中的对象都需要考虑线程安全问题
(2)有垃圾回收机制
2.堆内存溢出
报错提示
java.lang.OutofMemoryError :java heap space. 堆内存溢出
3.堆内存诊断
(1)jps:查看当前系统中又哪些java进程
(2)jmap:查看堆内存占用情况
(3)jconsole:图形界面的,多功能检测工具,可以连续检测
(4)jvirsalvm
诊断演示
运行代码之后,输入jps查看进程id
使用jmap -heap pid查看内存占用情况
日志打印1时的内存占用
日志打印2时的内存占用
日志打印3时的内存占用
使用jconsle查看内存情况
在jconsle可以实时看到内存的变化情况
4.案例
垃圾回收之后,内存占用仍然很高
使用jconsle执行gc命令,查看内存变化情况
使用jmap进一步查看内存各个代的占用情况
使用jvisualvm继续定位
找对最大的对象为一个list数组
进入list数组,可以看到数组中具体是信息
案例源码
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。