目录
程序计数器
栈
虚拟机栈
垃圾回收是否涉及栈内存?
栈内存分配越大越好吗?
方法内的局部变量是否线程安全?
栈内存溢出
本地方法栈
堆
方法区
先看内存图总览
程序计数器
定义:全称P r o g r a m C o u n t e r R e gis t e r 程 序 计 数 器 ( 寄 存 器 )
作 用 : 是 记 住 下 一 条j v m 指 令 的 执 行 地 址
特点:
是 线 程 私 有 的
不 会 存 在 内 存 溢 出(java中唯一一个不会存在内存溢出的区域)
作用:java程序要想执行,首先会编译成字节码,也就是计算机能够看懂的二进制文件,但是呢操作系统并不能认识这些二进制字节码,比如一条命令很有可能产生很多行字节码,这时候就需要程序计数器告诉操作系统,下一句将要执行哪句命令
0: getstatic #20 // PrintStream out = System.out;
3: astore_1 // --
4: aload_1 // out.println(1);
5: iconst_1 // --
6: invokevirtual #26 // --
9: aload_1 // out.println(2);
10: iconst_2 // --
11: invokevirtual #26 // --
14: aload_1 // out.println(3);
15: iconst_3 // --
16: invokevirtual #26 // --
19: aload_1 // out.println(4);
20: iconst_4 // --
21: invokevirtual #26 // --
24: aload_1 // out.println(5);
25: iconst_5 // --
26: invokevirtual #26 // --
在物理上是通过CPU中的寄存器来实现的,寄存器读取速度非常的快
程序计数器还有一个作用:多线程中,如果当前线程的时间片用完了,就需要程序计数器记录当前的线程状态,去执行其他的线程,因此它必须是线程私有的
栈
栈的数据结构特点就好比子弹夹,后放进去的子弹先打出来
栈可以看做为栈帧组成的
栈帧--每个方法运行时需要的内存
虚拟机栈
每个线程运行时所需要的内存,称为虚拟机栈
每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
垃圾回收是否涉及栈内存?
并不涉及,方法执行完就会出栈,销毁栈帧
栈内存分配越大越好吗?
并不是,一般采用默认的分配空间
方法内的局部变量是否线程安全?
如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全
栈内存溢出
栈帧过多导致栈内存溢出(比如死循环)
栈帧过大导致栈内存溢出(一般不会出现,栈帧一般存着方法变量和局部参数,一个int类型才占用4bite)
本地方法栈
给本地方法运行提供一个内存区
这个部位存的是非java部分的代码,有时候不能够直接去和操作系统打交道,底层可能要用到本地方法(可能用c或者C++写的)去调用,这些本地方法就存在本地方法栈
堆
堆 :通过 new 关键字,创建对象都会使用堆内存
特点:
它是线程共享的,堆中对象都需要考虑线程安全的问题
有垃圾回收机制
方法区
存的是和类有关的信息,也存在类加载器(加载二进制字节码)
方法区也会内存溢出
方法区的实现:
在1.8之前是采用的永久代的形式,并且字符串常量池也在方法区
在1.8之后就采用了元空间的形式,字符串常量池被移到了堆中,默认使用的是系统内存的空间,一般不会导致内存溢出,但是理论上是可以的,加载的类过多就会出现溢出