JVM入门-内存结构

一、程序计数器(PC Register)---> 寄存器

1、定义:

2、作用:

记住下一条程序指令

3、特点:

  • 线程私有
  • 不会存在内存溢出

二、虚拟机栈(JVM Stacks)

1、栈数据结构:

2、定义:

  • 每个线程运行时需要的内存,称为虚拟机栈
  • 每个栈由多个栈帧(Frame)组成,对应每次方法调用时所以占用的内存
  • 每个线程只能有一个活动栈帧(顶栈帧),对应着当前正在执行的那个方法

3、问题辨析

  • 垃圾回收是否涉及栈内存?

不会,栈内存所占用的空间就是一次次栈帧内存,而栈帧内存在一次次方法调用结束后,会被弹出栈(自动被回收),不需要GC处理。

  • 栈内存分配越大越好吗?

-Xxs size : 为栈内存指定大小。物理内存空间是定值,栈内存越大,则线程数量越少(本质就是个除法)。

  • 方法内的局部变量是否是线程安全?

不一定:例如下列的三个例子是否是线程安全?

第一个:私有局部变量,其他线程不会访问到。是

第二个:对象作为方法的参数传进,则其他的线程有可能访问到,这个对象有可能是被共享的。否

第三个:将对象作为返回值,虽然此时sb任然是局部变量,但是其他线程任然有可能访问。否

总结:考虑一个变量是不是线程安全不仅仅只是看变量是不是该方法内的局部变量,还需要考虑该变量是否逃离了该方法的作用范围,如果其作为返回值逃离了作用范围,则其线程不安全。

  • 如果方法内局部变量没有逃离方法的作用范围,它是线程安全的
  • 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全
    public static void main(String[] args){

}
    public static void m1(){
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
}
     

    public static void m2(StringBuilder sb){
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
}

    public static StringBuilder m3(){
        sb.append(1);
        sb.append(2);
        sb.append(3);
        return sb;
}
}                 

3、栈内存溢出 (StackOverflowError)

  • 栈帧过多(无限递归调用)导致栈内存溢出

下方代码为案例1 :计数次数表示栈帧个数。

public class Demo1_2{
    private static int count;

    public static void main(String[]args){
        try{
            method1();
            }catch (Throwable e){
                e.printstackTrace();
                System.out.println(cou);
                }
}

     private static void method1(){
        count++;
        method1();
    }
}
  • 栈帧内存过大导致栈内存溢出(一般不会)

4、线程运行诊断

案例1:cpu占用过多。

  • top:检测后台进行cpu占用率.

ps: 线程对CPU的占用 H : 打印进程里所有线程信息 -eo :输出内容

pid : 进程id tid : 线程ID %cpu:占cpu |grep 进程id 

  • ps H -eo pid,tod,%cpu|grep 进程id
  • jstack 进程id。  进程中所有Java线程列出来
    • 可以根据id找到有问题的线程,进一步定位到问题代码的源码行数

注意jstack中的id为16进制。

案例2:程序运行很长时间没有结果(死锁)

2号线程先睡眠,此时1号线程锁住a,并且1号线程开始睡眠。

2号线程苏醒后锁住b,并且开启等待a。

1号线程苏醒,并且开启等待b。

死锁。

public class Demo1_3{
    static Aa new A();
    static Bb new B();


    public static void main(String[]args)throws InterruptedException{

            new Thread((a)->{
                synchronized (a){
                    try{
                        Thread.sleep(millis:2000);
                        }catch (InterruptedException e){
                            e.printstackTrace();
                            }
                            synchronized (b){
                                System.owt.println("获得了a和b);
                            }
                })start();

                Thread.sleep(millis:1000);
                    new Thread(()->{
                        synchronized (b){
                            synchronized (a){
                                System.out.println("获得了a和b");
                            }
                        }
                }).start();
        }

}

三、本地方法栈(Native Method Stacks)

  • JVM调用本地方法时的栈区。
  • native:方法底层实现(C/C++),通过Java与之相连。

四、堆(Heap)

  • 线程共享区

1、定义

通过new关键字,创建对象都会使用堆内存

2、特点

  • 线程共享,堆中的对象都需要考虑线程安全问题
  • 有垃圾回收机制

3、堆内存溢出(OOM(Out Of Memory):Java heap space)

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);/hello,hellohello,hellohellohellohello ..
                aaa;/hellohellohellohello
                i+;
            }
                }catch (Throwable e){
                    e.printstackTrace();
                    System.out.println(i);
                    }
   }

4、堆内存诊断

public class Demo1 4{
    public static void main(String[]args)throws InterruptedException{
        System.out.println("1...");
        Thread.sleep(millis:30000);
        byte[]array = new byte[1024 1024 10];//10 Mb
        System.out.println("2...");
        Thread.sleep(millis:30000);
        array = null;
        System.gc();
        System.out.println("3...");
        Thread.sleep(millis:1000000L);
    }
}

1、 jsp工具

  • 查看当前系统中有哪些java进程

2、jmap工具

  • 查看堆内存占用情况

3、jconsole工具

  • 图形界面,多功能连续监测

五、方法区(Method Area)

  • 线程共享区

1、定义:

The Java Virtual Machine has a method area that is shared among all Java Virtual
Machine threads.The method area is analogous to the storage area for compiled code
of a conventional language or analogous to the "text"segment in an operating system
process.It stores
per-class structures such as the run-time constant pool,field and
method data,and the code for methods and constructors
,including the special
methods
($2.9)used in class and instance initialization and interface initialization.

The method area is created on virtual machine start-up.Although the method area is
logically part of the heap,simple implementations may choose not to either garbage
collect or compact it.This specification does not mandate the location of the method
area or the policies used to manage compiled code.The method area may be of a
fixed size or may be expanded as required by the computation and may be contracted
if a larger method area becomes unnecessary.The memory for the method area does
not need to be contiguous.

  • If memory in the method area cannot be made available to satisfy an
    allocation request,the Java Virtual Machine throws an outofMemoryError.

2、方法区内存溢出

1.8方法区被移到了本地内存

  • 1.8以前会导致永久代内存溢出(OOM:(PermGen space))
  • -XX:MaxPermSize=8m:永久代最大内存设置

  • 1.8以后会导致元空间内存溢出(OOM:Metaspace)
  • 元空间默认为系统内存 -XX:MaxMetaspaceSize=8m:虚拟机设置最大元空间内存

场景

  • spring
  • Mybatis

3、运行时常量池

  • 常量池,就是一张常量表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量等信息
  • 运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池(放到内存上时),并把里面的符号变为真实地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值