jvm指令是二进制字节码。
作用记住下一条jvm指令的执行地址,
解释器根据程序计数器中存储的字节码指令的地址来找下一条执行的指令
特点- 是线程私有的,为了防止线程来回切换后不知道该执行那条指令。
- 不会存在内存溢出。
是线程运行需要的内存空间
存放在栈中的各部分叫做栈帧,栈帧的定义是每个方法运行时所需要的内存
每个线程只能由一个活动栈帧,对应着当前正在执行的那个方法
- 垃圾回收是否涉及栈内存?
不涉及,因为栈内存在方法调用结束后都会自动弹出栈。
- 栈内存分配越大越好吗?
**不是,栈内存越大线程数就会越少,因为物理内存大小是固定的,栈内存越大,可运行线程就越少。**比如,一个线程使用栈内存,假设使用1M的内存,物理内存500M,理论上就可以有500个线程同时运行。如果每个线程设置2M,那么只能同时有250个线程运行。所以栈内存分配越大并不是越好,它分配大了通常只是能够进行多次的方法递归调用,而不会增快程序的运行效率,反而会影响线程数目的变少。一般采用默认的就可以,不必在程序启动的时候手动修改。
- 方法内的局部变量是否线程安全
当方法内局部变量没有逃离方法的作用访问时线程安全,因为一个线程对应一个栈,每调用一个方法就会新产生一个栈桢,都是线程私有的局部变量,当变量是static时则不安全,因为是线程共享的。
例外:在有static变量时或局部变量作为参数时或者局部变量应用了引用了对象作为返回值返回时都是线程不安全的。
局部变量会存放在栈里。如果一个变量需要跨越方法的边界,就必须创建在堆里。
内存溢出- 栈帧过多导致栈内存溢出
- 栈帧过大导致栈内存溢出
-
第一步
-
第二步
- 案例1:cpu占用过多
在linux系统中出现该问题时,用top命令定位哪个进程对cpu的占用过高,然后用
ps H -eo pid,tid,%cpu | grep 进程id(进一步找寻线程)或者jstack 进程id
然后将十进制的进程id换算成十六进制(nid是进程)来找对应的线程
- 案例2:程序迟迟不响应
与上面解决方法相同
本地方法栈用来给本地方法提供内存的栈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZhEUA5j-1659101687855)(C:UserswjlAppDataRoamingTyporatypora-user-imagesimage-20220729201816825.png)]
堆- 通过new关键字创建的对象都会使用堆内存
- 他是线程共享的,堆中对象都需要考虑线程安全的问题
- 有垃圾回收机制
- 查看当前系统中有哪些java进程
- 查看堆内存占用情况(只能查询某一个时刻的情况)
- 图形界面的多功能的检测工具,可以连续监测
- 线程共享的
存储了跟类相关的信息,如:成员变量、方法、构造器及常量池等。
在1.8之前方法区的实现叫永久代,就是使用堆的一部分作为方法区。而1.8之后方法区的实现叫元空间,使用的是本地内存也就是系统内存。
组成(常量池前少写了运行时) 方法区内存溢出 运行时常量池-
javac helloworld.java //将helloworld类编译成class文件
-
javap 反编译工具(javap -v helloworld.class)
常量池:就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量
等信息。
运行时常量池:常量池是 .class 文件中的,当该类被加载进虚拟机,它的常量池信息就会放入运行时常量
池,并把里面的符号地址变为真实的内存地址



