一、程序计数器

程序计数器内存很小,可以看作是当前线程所执行字节码的行号指示器

有了它,程序就能被正确的执行。

因为有线程切换的存在,则每个线程必须有各自独立的程序计数器,即线程私有的内存。

这里再解释一下什么是线程切换,线程切换指的是:

单处理器在执行多线程时所进行的线程切换,多线程的交替运行会产生同时运行的错觉。

程序计数器不会发生OOM原因:

占用内存非常小,当线程结束时程序计数器也会随之回收。

二、本地方法栈与虚拟机栈

栈是stack的翻译,那stack又是什么?

在英文语境中,stack指的是一摞盘子堆叠起来、一摞书堆叠起来的这种状态,也就是 a stack of books. 借这种现实物理情境来描述计算机中的数据结构。

这种结构的特征就是LIFO, Last In First Out, 即后进先出

也就是,一摞盘子,你只能一个一个往上堆,也只能一个一个从顶上往外取,对应**入栈和出栈(弹栈)**的操作。

以上是对栈这种结构的解释。

接下来说这两种栈结构:Native Method Stack 和 JVM stack.

栈是线程私有的,它的生命周期和线程是相同的。

栈里面保存栈帧

什么是栈帧

每个方法执行时都会创建一个栈帧。栈帧存储了局部变量表、操作数栈、动态连接和方法出口等信息。每个方法从调用到运行结束的过程,就对应着一个栈帧在栈中入栈到出栈的过程

栈有可能出现什么异常?

StackOverflowErrorOutOfMemoryError

前者主要是深度递归和复杂嵌套方法调用造成。

后者的话发生在栈在进行动态扩展的时候,也就是说 jvm 实现中栈的大小此时是不固定的,因为线程操作需要更多的栈空间而在申请内存的时候失败就会抛出OutOfMemoryError错误。

JVM 中的栈包括 Java 虚拟机栈和本地方法栈。

两者的区别就是:

Java 虚拟机栈为 JVM 执行 Java 方法服务,本地方法栈则为 JVM 使用到的 Native 方法(比如C或C++)服务。

四、堆

Heap有什么特征?

  • • JVM管理的最大内存区域

  • • 线程共享

  • • 存放对象实例

  • • 内存空间可以物理上不连续

  • • 垃圾回收的主要区域

关于垃圾回收的内容这里不展开讲了。

五、方法区

JVM规范把方法区描述为堆的一个逻辑部分,但有一个别名叫Non-Heap,即Heap中的Non-heap, 也是说明它和堆其实还是不一样的。

方法区有什么特征?

• 线程共享

• 存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

• 垃圾回收较少出现,甚至可选择不进行垃圾回收

方法区的垃圾回收主要针对常量池的回收和对类的卸载

这里主要说一下运行时常量池:

Class文件中除了有类的版本、字段、方法、接口等描述信息外还有一项常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

这里出现了两个常量池,它们是不一样的,一个叫常量池,一个叫运行时常量池(Runtime Constant Pool), 运行时常量池具备动态性,那怎么理解动态性呢?

就是说除了编译期产生的常量进入了常量池在类加载后又紧接着进入了运行时常量池以外,运行期间新的常量也会进入运行时常量池。

关于类加载的介绍我们再单独写一篇。

《学一点关于JVM类加载的知识》

下面举一些例子把这里具体搞搞清楚。

常量池有什么用 ?

**优点:**常量池避免了频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。

下面具体讲一下字符串常量池(String常量池):

String 是由 final 修饰的类,是不可以被继承的。通常有两种方式来创建对象。

//1、这种存在Heap中,每次new都会创建一个全新对象
String str = new String("abcd");
 
//2、这种是在栈上创建对象引用变量str,指向字符串常量池中的“abcd”(没有的话新建一个)
String str = "abcd";

关于字符串 + 号连接问题:

对于字符串常量的 + 号连接,在程序编译期,JVM就会将其优化为 + 号连接后的值。所以在编译期其字符串常量的值就确定了。

String a = "a1";   
String b = "a" + 1;   
System.out.println((a == b)); //result = true  
 
String a = "atrue";   
String b = "a" + "true";   
System.out.println((a == b)); //result = true 
 
String a = "a3.4";   
String b = "a" + 3.4;   
System.out.println((a == b)); //result = true 

关于字符串引用 + 号连接问题:

对于字符串引用的 + 号连接问题,由于字符串引用在编译期是无法确定下来的,在程序的运行期动态分配并创建新的地址存储对象

    public static void main(String[] args){
       String str1 = "a";
       String str2 = "ab";
       String str3 = str1 + "b";
       System.out.print(str2 == str3);//false
    }

通过 jad 反编译工具,分析上述代码到底做了什么。

    public class TestDemo{
    public TestDemo(){
    }
    public static void main(String args[]){
        String s = "a";
        String s1 = "ab";
        String s2 = (new StringBuilder()).append(s).append("b").toString();
        System.out.print(s1 = s2);
    }
}

发现 new 了一个 StringBuilder 对象,然后使用 append 方法优化了 + 操作符。new 在上创建对象,而 String s1=“ab”则是在常量池中创建对象,两个应用所指向的内存地址是不同的,所以 s1 == s2 结果为 false。

这里引出一个实际开发中关于字符串拼接的问题。就是尽量不要在 for 循环中使用 + 号来操作字符串

因为如果用“+”号的话,每次循环都会创建和销毁一个StringBuilder对象,这样还不如在循环外创建一个StringBuilder对象,然后使用append方法。

    public static void main(String[] args){
        StringBuilder s = new StringBuilder();
        for(int i = 0; i < 100; i++){
            s.append("a");
        }
    }

使用final修饰的字符串

    public static void main(String[] args){
        final String str1 = "a";
        String str2 = "ab";
        String str3 = str1 + "b";
        System.out.print(str2 == str3);//true
    }

final 修饰的变量是一个常量,编译期就能确定其值。所以 str1 + "b"就等同于 "a" + "b",所以结果是 true。

String对象的intern方法。

    public static void main(String[] args){
        String s = "ab";
        String s1 = "a";
        String s2 = "b";
        String s3 = s1 + s2;
        System.out.println(s3 == s);//false
        System.out.println(s3.intern() == s);//true
    }

通过前面学习我们知道,s1+s2 实际上在堆上 new 了一个 StringBuilder 对象,而 s 在常量池中创建对象 “ab”,所以 s3 == s 为 false。

但是 s3 调用 intern 方法,返回的是s3的内容(ab)在常量池中的地址值。所以 s3.intern() == s 结果为 true。


往期推荐:

● 师爷,翻译翻译什么叫AOP

终于搞懂动态代理了!

● 学会@ConfigurationProperties月薪过三千

● 0.o?让我看看怎么个事儿之SpringBoot自动配置

● 不是银趴~是@Import!

● Java反射,看完就会用

复习一下JVM内存结构的更多相关文章

  1. JVM学习十二 - (复习)JVM内存结构

    JVM 内存结构 Java 虚拟机的内存空间分为 5 个部分: 程序计数器 Java 虚拟机栈 本地方法栈 堆 方法区 JDK 1.8 同 JDK 1.7 比,最大的差别就是:元数据区取代了永久代.元 ...

  2. jvm系列(二):JVM内存结构

    JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...

  3. JVM内存结构之三--持久代

    本文会介绍一些JVM内存结构的基本概念,然后很快会讲到持久代,来看下Java SE 8发布后它究竟到哪去了. 基础知识 JVM只不过是运行在你系统上的另一个进程而已,这一切的魔法始于一个java命令. ...

  4. JVM内存结构

    前言 在Java语言开发过程中,out of memory错误是很常见的一种错误.对于JVM的内存结构有更深入的了解,更更好的帮我们排查此类问题,有效的避免此类问题发生.在JAVA 8中内存结构有进行 ...

  5. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  6. JVM内存结构,运行机制

    三月十号,白天出去有事情出去了一天,晚上刚到食堂就接到阿里电话, 紧张到不行,很多基础的问题都不知道从哪里说了orz: 其中关于JVM内存结构,运行机制,自己笔记里面有总结的,可当天还是一下子说不出来 ...

  7. JVM内存结构简单认知

    关于JVM的面试传送门:https://blog.csdn.net/shengmingqijiquan/article/details/77508471 JVM内存结构主要划分为:堆,jvm栈,本地方 ...

  8. 【JVM】JVM内存结构 VS Java内存模型 VS Java对象模型

    原文:JVM内存结构 VS Java内存模型 VS Java对象模型 Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清 ...

  9. 【转】JVM内存结构 VS Java内存模型 VS Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途. 其中有些区域随着虚拟机进程的启动而 ...

  10. jvm系列二、JVM内存结构

    原文链接:http://www.cnblogs.com/ityouknow/p/5610232.html 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemory ...

随机推荐

  1. Spring Cloud 系列:Seata 中TCC模式具体实现

    概述 https://seata.io/zh-cn/docs/dev/mode/tcc-mode https://seata.io/zh-cn/docs/user/mode/tcc TCC模式与AT模 ...

  2. 码农的转型之路-IoTBrowser(物联网浏览器)雏形上线

    消失了半个月闭门造轮子去了,最近干了几件大事: 1.工控盒子,win10系统长时间跑物联网服务测试.运行快2周了,稳定性效果还满意,除了windows自动更新重启了一次. 2 .接触了一些新概念MQT ...

  3. Tidb异名恢复Mysql数据库的过程

    Tidb异名恢复Mysql数据库的过程 背景 先说坑: TiDB备份恢复的方式 1. mysqldump + mysql source 的方式. 2. mydumper + loader tidb 的 ...

  4. [转帖]AlertManager 配置邮箱告警

    http://www.mydlq.club/article/126/ 2022-12-02 13:17:00KUBERNETESPROMETHEUSALERTMANAGER 文章目录 一.邮箱告警说明 ...

  5. [转帖]MySQL InnoDB存储引擎大观

      https://baijiahao.baidu.com/s?id=1709263187856706948&wfr=spider&for=pc MySQL InnoDB 引擎现在广为 ...

  6. [转帖]VCSA证书过期问题处理

    1.  故障现象 2022年10月25日,登陆VC报错. 按照报错信息,结合官方文档,判断为STS证书过期导致. vCenter Server Appliance (VCSA) 6.5.x, 6.7. ...

  7. JVM启动参数脚本的再学习与研究

    JVM启动参数脚本的再学习与研究 摘要 学无止境 前段时间一直再研究JVM参数调优. 但是最近也在想不应该仅研究如何调优. 因为不管怎么设置, 总有猪队友会把环境搞崩. 所以应该想办法在无人值守的情况 ...

  8. element-plus 按需引入将英文组件修改为中文

    element-plus 默认是英文组件:如下图 将它设置为中文组件 app.vue文件 <template> <el-config-provider :locale="l ...

  9. 基于go-restful实现的PoW算力池模型

    最开始知道区块链是在17年初,当时因为项目压力不大,开始研究比特币源码.对于比特币中提到的Proof of Work,当时只是一眼带过,并没有详细查看过相关的代码.在最近的项目中,考虑到性能的要求,需 ...

  10. Volatility 内存数字取证方法

    计算机数字取证分为内存取证和磁盘取证,活取证与死取证,不管是那种取证方式,都应尽量避免破环犯罪现场,例如通过内存转储工具对内存进行快照,通过磁盘克隆工具对磁盘进行克隆,方便后期的分析工作,这里将研究内 ...