JVM学习笔记——内存结构篇( 三 )

虚拟机栈内存溢出问题虚拟机栈在默认情况下为1024K,正常情况下不会溢出,但如果出现异常可能导致溢出
首先我们介绍一个改变虚拟机栈的方法:
// 在配置运行环境的Environment variables中进行配置(如下修改为256k)-Xss256k然后我们介绍两种溢出情况:

  1. 栈帧过多
// 正常情况下我们的栈帧(方法)就算再多也不会导致内存溢出,但是如果我们发生了无限递归异常呢?// 我们在这个方法中递归调用本身,就会导致不断有栈帧加入到虚拟机栈中,最终导致虚拟机栈内存溢出package cn.itcast.jvm.t1.stack;/** * 演示栈内存溢出 java.lang.StackOverflowError * -Xss256k */public class Demo1_2 {private static int count;public static void main(String[] args) {try {method1();} catch (Throwable e) {e.printStackTrace();System.out.println(count);}}private static void method1() {count++;method1();}}
  1. 栈帧过大
/*我们仅仅是来解释这个溢出想法但实际上我们的默认虚拟机栈大小为1M,是不可能出现栈帧过大的情况的~*/虚拟机线程实际问题运行判断我们会给出两个实际案例来进行讲解:
  1. CPU占用过多
// 我们的项目通常都会运行在Linux服务器上,所以我们下面通过Linux来介绍方法// 首先通过top定位哪个进程对cpu的占用过高top // 然后我们通过ps命令进一步查看哪个线程引起cpu占用率过高ps H -eo pid,tid,%cpu | grep 进程id// 最后我们查看线程具体问题jstack 进程id// 最后我们到我们的项目代码中进行检查会发现问题(可能是死循环之类的)package cn.itcast.jvm.t1.stack;/** * 演示 cpu 占用过高 */public class Demo1_16 {public static void main(String[] args) {new Thread(null, () -> {System.out.println("1...");while(true) {}}, "thread1").start();new Thread(null, () -> {System.out.println("2...");try {Thread.sleep(1000000L);} catch (InterruptedException e) {e.printStackTrace();}}, "thread2").start();new Thread(null, () -> {System.out.println("3...");try {Thread.sleep(1000000L);} catch (InterruptedException e) {e.printStackTrace();}}, "thread3").start();}}
  1. 程序运行过久没有结果
/*我们采用之前相同的方法来进行判断,一般运行过久没有结果都是发生死锁问题*/package cn.itcast.jvm.t1.stack;/** * 演示线程死锁 */class A{};class B{};public class Demo1_3 {static A a = new A();static B b = new B();public static void main(String[] args) throws InterruptedException {new Thread(()->{synchronized (a) {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (b) {System.out.println("我获得了 a 和 b");}}}).start();Thread.sleep(1000);new Thread(()->{synchronized (b) {synchronized (a) {System.out.println("我获得了 a 和 b");}}}).start();}}本地方法栈这小节我们来介绍JVM内存结构中的本地方法栈
本地方法简介首先我们先来简单介绍一下本地方法:
  • JVM属于Java层次的东西,是无法通过Java与底层进行交互
  • 这时我们就需要一些采用C,C++语言的方法来与底层进行交互,这种方法就被称为本地方法
本地方法特点:
  • 本地方法大多设置为接口,其返回值类型为native
  • 我们常见的本地方法包括有Object中的clone方法,hashCode方法,wait方法等
本地方法栈简介本地方法栈自然也不难理解:
  • 本地方法栈就是一个存储本地方法的栈
  • 其原理与虚拟机栈完全相同,只不过里面的栈帧变为了本地方法而已
堆这小节我们来介绍JVM内存结构中的堆
堆简介首先我们需要先理解什么是堆:
  • 堆的本体通常可以被看做一棵完全二叉树的数组
那么堆里面通常会储存什么东西:

经验总结扩展阅读