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

虚拟机线程实际问题运行判断我们会给出两个实际案例来进行讲解:

  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内存结构中的堆
堆简介首先我们需要先理解什么是堆:
  • 堆的本体通常可以被看做一棵完全二叉树的数组
那么堆里面通常会储存什么东西:
  • 通过关键字new创建的对象都会使用堆来存储
堆具有以下基本特点:
  • 有垃圾回收机制
  • 堆是线程共享的 , 堆中的所有对象都需要考虑线程安全问题
堆内存溢出问题堆通常是用于存储new创建的对象 , 它的默认大小同样为1024K , 我们提供方法来改变堆内存:
// 在配置运行环境的Environment variables中进行配置(如下修改为256k)-Xmx8m堆出现内存溢出问题只有一种情况就是创建对象过多:
/*正常情况下,我们的创建的对象在不使用的情况下就会被自动垃圾回收但如果出现异常,导致我们不断创建新对象且保存就对象就会导致堆内存溢出*/package cn.itcast.jvm.t1.heap;import java.util.ArrayList;import java.util.List;/** * 演示堆内存溢出 java.lang.OutOfMemoryError: Java heap space * -Xmx8m */public class Demo1_5 {public static void main(String[] args) {int i = 0;try {List<String> list = new ArrayList<>();String a = "hello";while (true) {list.add(a); // 这里将旧对象保存下来a = a + a;// 这里不断创建新对象i++;}} catch (Throwable e) {e.printStackTrace();System.out.println(i);}}}堆内存问题诊断我们在正常运行中堆的内存占有是非常重要,因此JVM为我们提供了四种方法来检查堆内存问题
首先我们给出用于诊断堆内存问题的参考代码:
package cn.itcast.jvm.t1.heap;/** * 演示堆内存 */public class Demo1_4 {public static void main(String[] args) throws InterruptedException {// 第一阶段:没有对象System.out.println("1...");Thread.sleep(30000);// 第二阶段:制造一个对象,占用堆byte[] array = new byte[1024 * 1024 * 10];System.out.println("2...");Thread.sleep(20000);// 第三阶段:释放对象,并进行垃圾回收,这时堆变小array = null;System.gc();System.out.println("3...");Thread.sleep(1000000L);}}我们的JVM为我们提供了四种方法来检测堆的状况:
  1. jps工具
// jps用于查看当前系统中有哪些java进程// 我们直接在IDEA的输入台输入即可jps

推荐阅读