上一篇介绍了C++和Java编译的区别和Java独有的网络编程,线程管理。这一篇主要介绍一下两者在程序运行时的内存空间。

内存分布

项目 C++ 程序 Java 程序(使用 JVM)
编译结果 直接生成机器码(如 .exe 编译成 .class 字节码
执行方式 操作系统直接加载执行 需要 JVM 加载 .class 文件
启动时发生的事 操作系统创建进程并加载程序 操作系统创建 JVM 进程,JVM 加载类
所属进程 你的 C++ 程序本身就是进程 Java 程序是运行在 JVM 进程中的一段代码
内存分配方式 程序直接使用虚拟内存 JVM 申请虚拟内存再分出堆、栈等区域

C++的程序启动过程,是操作系统创建一个用户进程,运行C++程序。一个程序就是一个新的用户进程,有自己独立的内存空间(虚拟)。

Java的程序启动过程,与C++相比较,只是多了JVM的启动过程。Java程序也是一个进程,但是JVM的“客人”,必须在 JVM 虚拟机中运行。

由此可以判断出,为什么Java的线程管理这么方便,因为它的线程管理不依赖于操作系统,自由度也就更高。

C++程序内存分布

+-------------------+  高地址
| 栈区(Stack) | 局部变量、函数调用帧
+-------------------+
| 堆区(Heap) | new / malloc 分配的内存
+-------------------+
| 全局区(静态区)| static 和全局变量
+-------------------+
| 代码段(Text) | 程序指令
+-------------------+ 低地址

程序能够使用的最大内存为4GB,这个大小是PC指针能够寻址的最大范围,也是你的总线的位数。高位地址是内核空间,用来执行系统调用。在C/C++中内存分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。

  • 静态内存分配:编译时分配。包括:全局、静态全局、静态局部三种变量。
  • 动态内存分配:运行时分配。包括:栈(stack): 局部变量。堆(heap): c语言中用到的变量被动态的分配在内存中。(malloc或calloc、realloc、free函数)

在 C++ 中,你创建的对象是放在「堆区」还是「栈区」,取决于你如何创建它。普通变量或自动对象创建在栈区,而newmalloc的对象则创建在堆区。

Java程序内存分布

Java 的内存分布由JVM管理,而C++的内存分布由操作系统直接管理。

Java的JVM是在操作系统虚拟内存之上的一个“虚拟机”,它向操作系统申请一块内存,然后自己划分成方法区、堆、栈等区域进行管理。Java虚拟机先运行,Java程序被“加载进去”。

+-------------------------+ 高地址
| 元空间 (Metaspace) | 存类信息、静态变量、常量池(JDK8之后)
| 方法区(永久代,已废弃)| 存储类结构、方法数据等(JDK7及以前)
+-------------------------+
| Java 堆(Heap) | 对象实例分配的内存,大部分对象都在这里
+-------------------------+
| 虚拟机栈(每线程一个) | 方法调用、局部变量表、操作数栈等
+-------------------------+
| 程序计数器 | 当前执行字节码的行号指示器
+-------------------------+
| 本地方法栈 | 用于执行 native 方法
+-------------------------+ 低地址

上图可知,Java的内存区包括两部分:线程私有部分———虚拟机栈、本地方法栈、程序计数器,公共部分——堆、本地内存。

Java方法和Native方法

Java 方法是使用 Java 语言编写的方法,最终被编译成字节码(.class 文件中的Code属性),由 JVM 直接解释或编译执行。Native 方法是使用非 Java 语言(通常是 C/C++)编写的方法,并通过 JNI(Java Native Interface) 在 JVM 中调用。

私有部分

  • 程序计数器:这个和CPU的PC指针是一样的,CPU的PC指针指向当前运行指令的物理内存地址,后续取指令,解析指令,运行指令。线程的程序计数器记录的是正在执行的字节码指令地址,这是一个增量,基于当前正在执行的方法的字节码数组上增加。

  • 虚拟机栈:每一个线程在执行代码时,都需要栈区来记录局部变量、返回地址等信息,Java方法调用都是通过虚拟机栈来实现的,栈由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈(栈顶存放有当前方法调用之后的返回值)、动态链接(调用当前方法所需的引用)、方法返回地址(方法返回后继续执行的位置,也就是调用方法时当前PC的值)。所以对于线程而言,若要调用一个方法,然后返回至原来的位置,流程是:

    1. PC指针保存在当前栈帧的方法返回地址,创建新的栈帧,将参数保存在局部变量表,动态链接区对符号引用进行解析,将新的栈帧压栈。

    2. PC指针指向新的方法,开始执行字节码,将产生的变量和操作数保存在局部变量表和操作数栈。

    3. 执行完方法后,将返回值保存在操作数栈栈顶。将栈帧弹出,PC指针恢复为新的栈顶的方法返回地址,从弹出栈帧的操作数栈栈顶取执行结果。

  • 本地方法栈:和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。

每个线程所执行的“代码”(即类的字节码)在方法区或堆中共享,自己的“变量”在JVM 栈(局部变量表)中,当前线程正在执行的字节码位置保存在程序计数器中。当线程需要修改共享区域时,使用锁。

共有部分

比较项 堆(Heap) 方法区(Method Area)
存放内容 实例对象 类的元数据、方法信息、静态变量、常量池等
作用 运行时对象分配 加载类结构信息、JIT 编译缓存、静态数据
生命周期 随 JVM 存在 随 JVM 存在
垃圾回收 对象回收 类卸载时才回收(较少发生)

上表用来比较堆和方法区的区别,也就是说方法区存在的只是方法,真正的实例化对象在堆,一个方法可以有很多个实例化对象。

  • 堆:此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage Collected Heap)。GC堆通过分代垃圾收集算法,控制对象年龄,更好地回收内存,或者更快地分配内存。

  • 字符串常量池:是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。JDK 1.7以后从永久代移动到了堆中,来实现高效的内存回收。

  • 方法区:方法区属于是当虚拟机要使用一个类时,它需要读取并解析 Class 文件获取相关信息,再将信息存入到方法区。方法区会存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

  • 运行时常量池:字面量是源代码中的固定值的表示法,即通过字面我们就能知道其值的含义。字面量包括整数、浮点数和字符串字面量。常见的符号引用包括类符号引用、字段符号引用、方法符号引用、接口方法符号。总的来说:编译器能确定的字面量和常量,符号引用。

符号引用(Symbolic Reference)是 Java 字节码中用于表示类、字段、方法等的一种 “符号形式” 的间接引用,在类未加载或链接前,它还不是一个内存地址或直接指针,而是“名字”+“描述符”等信息的组合。

  • 直接内存:通过 JNI 的方式在本地内存上分配的。

参考资料

Java学习篇(二)—— C++和Java的区别之程序内存分布的更多相关文章

  1. Java学习笔记二十八:Java中的接口

    Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...

  2. Java学习笔记二十五:Java面向对象的三大特性之多态

    Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...

  3. Java学习笔记二十四:Java中的Object类

    Java中的Object类 一:什么是Object类: Object类是所有类的父类,相当于所有类的老祖宗,如果一个类没有使用extends关键字明确标识继承另外一个类,那么这个类默认继承Object ...

  4. Java 学习笔记 (二) Selenium WebDriver Java 弹出框

    下面这段实例实现了以下功能: 1. profile使用用户本地电脑上的 (selenium 3有问题.因为selenium 3把profile复制到一个temp文件夹里,但并不复制回去.所以每次打开仍 ...

  5. Java学习笔记二十六:Java多态中的引用类型转换

    Java多态中的引用类型转换 引用类型转换: 1.向上类型转换(隐式/自动类型转换),是小类型到大类型的转换: 2.向下类型转换(强制类型转换),是大类型到小类型的转换: 3.instanceof运算 ...

  6. 【转】java提高篇(二)-----理解java的三大特性之继承

    [转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...

  7. Java 学习(21):Java 实例

    Java 实例 本章节我们将为大家介绍 Java 常用的实例,通过实例学习我们可以更快的掌握 Java 的应用. Java 环境设置实例 //HelloWorld.java 文件 public cla ...

  8. 最新java学习路线:含阶段性java视频教程完整版

    最新java学习路线:带阶段性java视频教程版本 第一阶段:Java基础 学习目标: 掌握基本语法.面向对象.常用类.正则.集合.Io流.多线程.Nio.网络编程.JDK新特性.函数式编程 知识点细 ...

  9. Java 学习(7):java 日期时间 & 正则表达式

    目录 --- 日期时间 --- 正则表达式 日期时间:java.util 包提供了 Date 类来封装当前的日期和时间. Date 类提供两个构造函数来实例化 Date 对象. 构造函数:用于初始化对 ...

  10. Java 学习(17): Java 泛型

    Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说将 ...

随机推荐

  1. CSS那些事读书笔记-1

    背景 作为一个后端开发,曾经尝试过学习前端,但是总觉不得要领,照猫画虎,而公司里又有专业的前端开发,工作中几乎接触不到实际的前端任务,所以前端的技能田野一直是一片荒芜.但是笔者深知前端的技能对找工作和 ...

  2. JDK7-时间类、时间格式化类--java进阶day07

    1.Date类:表示时间的类 1.Date常用的构造方法 . 2.Date常用的成员方法 1.getTime:返回从时间原点到对象设定的时间之间的时间 2.setTime:将对象的时间设置为setTi ...

  3. study PostgreSQL【2-FireDAC连接PostgreSQL】

    就这么个简单问题,一下午时间.想想就憋屈. 那么牛逼哄哄FireDAC居然连接PostgreSQL出问题了.帮助中说的啥意思,咱也不明白.网上一通也是云里雾里. 上干货,具体点: TFDConnect ...

  4. study Rust-4【所有权】这个太重要了!

    由于Rust内存垃圾自动回收,那就得搞清楚这个所有权玩意.这个太重要了.因为关系到贯穿于你以后的程序编写. 几个概念: 一.移动 1.咱们一般语言,自己申请内存,自己管理和释放.就是new和free. ...

  5. 结合laravel深入理解php的服务容器和依赖注入

    原文:laravel 学习笔记 -- 神奇的服务容器 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于你对该容器的定义.当然,有这样一种容器,它存 ...

  6. win mysql实现主从同步(精简版)

    最近项目要弄读写分离,那首先要实现主从同步啊,网上教程很多,但大多都看得云里雾里,so,有了这个精简版: 主库my.ini添加配置: #数据库ID号, 为1时表示为Master,其中master_id ...

  7. C# 拓展方法( 一)

    总结:用处在不破坏原有类封装的情况下给它添加新的方法,这样可以不需要修改这个类的源代码,也不需要再另外的继承一个类添加方法. C#中的扩展方法及用途 - 森大科技 - 博客园 (cnblogs.com ...

  8. smail log插桩(模板)

    即插即用 后面都用hook了,但是为了方便,还是分享下吧 Log const-string v0, "MYTAG" const-string v1, "Message&q ...

  9. 【记录】Python3|将元组/列表/集合或字典解析成多个参数传入函数,以及定义可变参数函数

    [说人话版] 将元组/列表/集合或字典直接作为多个函数参数传入,只需要添加*或**即可. 样例如下. 在Python中,将元组.列表.集合或字典作为多个函数参数传入是一种非常方便的技巧,可以帮助我们在 ...

  10. 【记录】ChatGPT|近期三次更新一览(更新至2023年2月3日)

      如果你还没有使用过ChatGPT,可以先看看我的上一篇文章:[记录]ChatGPT|使用技巧与应用推荐(更新至2023年2月8日).   1月11号晚上,ChatGPT突然很多人都无法登录,包括我 ...