Atitit vm os内存管理 目录 1. 冯诺依曼结构、哈佛结构、改进型哈佛结构 1 1.1. 冯·诺依曼结构 1 1.2. 哈佛结构 2 1.3. 改进型的哈佛结构与哈佛体系结构差别 3 2.
Atitit vm os内存管理
目录
3.1.1. 局部表量表 操作数栈 动态链接 方法返回地址 4
4. Android 运行时 (ART) 和 Dalvik 虚拟机 6
6.1.2. 已初始化读写数据段(RW data -- Initialized Data Segment) 7
6.1.3. 未初始化数据段(BSS --Uninitialized Data Segment) 7
冯·诺依曼结构(von Neumann architecture)又称作普林斯顿体系结构(Princetion architecture)。冯·诺依曼结构的处理器使用同一个存储器,经由同一个总线传输。冯·诺依曼结构处理器具有以下几个特点:
- 必须有一个存储器;
- 必须有一个控制器;
- 必须有一个运算器,用于完成算术运算和逻辑运算;
- 必须有输入和输出设备,用于进行人机通信。
哈佛结构是一种将程序指令存储和数据存储分开的存储器结构,如下图所示。中央处理器首先到程序指令存储器中读取程序指令内容,解码后得到数据地址,再到相应的数据存储器中读取数据,并进行下一步的操作(通常是执行)。程序指令存储和数据存储分开,可以使指令和数据有不同的数据宽度,如Microchip公司的PIC16芯片的程序指令是14位宽度,而数据是8位宽度。
哈佛结构的微处理器通常具有较高的执行效率。其程序指令和数据指令分开组织和存储的,执行时可以预先读取下一条指令。
哈佛结构是指程序和数据空间独立的体系结构, 目的是为了减轻程序运行时的访存瓶颈。
哈佛结构能基本上解决取指和取数的冲突问题。
与冯.诺曼结构处理器比较,哈佛结构处理器有两个明显的特点:
(1).使用两个独立的存储器模块,分别存储指令和数据,每个存储模块都不允许指令和数据并存;
(2).使用独立的两条总线,分别作为CPU与每个存储器之间的专用通信路径,而这两条总线之间毫无关联。
后来,又提出了改进的哈佛结构,其结构特点为:
(1).使用两个独立的存储器模块,分别存储指令和数据,每个存储模块都不允许指令和数据并存;
(2).具有一条独立的地址总线和一条独立的数据总线,利用公用地址总线访问两个存储模块(程序存储模块和数据存储模块),公用数据总线则被用来完成程序存储模块或数据存储模块与CPU之间的数据传输;
(3).两条总线由程序存储器和数据存储器分时共用。
现在的处理器,依托CACHE的存在,已经很好的将二者统一起来了。现在的处理器虽然外部总线上看是诺依曼结构的,但是由于内部CACHE的存在,因此实际上内部来看已经类似改进型哈佛结构的了。
常量 静态变量
局部变量
对象
进程内存示意图.png
Stack空间(进栈和出栈)由操作系统控制,其主要储存函数地址、函数参数、局部变量等等,所以Stack空间不需要很大,一般几MB大小。
Heap空间由程序员控制,主要包括实例域、静态域、数组元素等,储存空间比较大,一般为几百NB到几GB。正是由于Heap空间由程序员管理,所以容易出现使用不当的问题(如内存泄漏),当然,Heap内存也是系统GC发生的区域
每个栈帧(见上图)内部都包含一组称为局部变量表的变量列表。栈帧中局部变量表的长度由编译期决定,并且存储于类或接口的二进制表示之中,即通过方法的code属性保存及提供给栈帧使用。
操作数栈
每个栈帧(见上图)内部都包含一个称为操作数栈的后进先出( Last-In-First-Out,LIFO)栈。栈帧中操作数栈的最大深度由编译期决定,并且通过方法的code属性保存及提供给栈帧使用。
动态链接 方法返回地址
每个栈帧内部都包含一个指向当前方法所在类型的运行时常量池的引用,以便对当前方法的代码实现动态链接。在class文件里面,一个方法若要调用其他方法,或者访问成员变量,则需要通过符号引用(symbolic reference) 来表
方法返回地址
方法执行时有两种退出情况:第一,正常退出,即正常执行到任何方法的返回字节码指令,如RETURN、IRETURN、ARETURN等;第二,异常退出。无论何种退出情况,都将返回至方法当前被调用的位置。方法退出的过程相当于弹出当前栈帧,退出可能有三种方式:
返回值压入上层调用栈帧。
异常信息抛给能够处理的栈帧。
PC计数器指向方法调用后的下一条指令。
Heap是OOM故障最主要的发源地,它存储着几乎所有的实例对象,堆由垃圾收集器自动回收,堆区由各子线程共享使用。通
早在JDK8版本中,元空间的前身Perm区(永久代)已经被淘汰。在JDK7及之前的版本中,只有Hotspot才有Perm区,译为永久代,它在启动时固定大小,很难进行调优,并且FGC时会移动类元信息。在某些场景下,如果动态加载类过多,容易产生Perm区的0OM。比如某个实际Web工程中,因为功能点比较多,在运行过程中,
摘抄整理自《深入理解jav
C++内存包括:栈,堆,全局/静态存储区,常量区,程序代码区。
C#内存包括:栈,堆,全局/静态存储区,常量区,自由存储区。
CLR:栈、GC堆、大对象堆。
,C#之内存分配
在C#中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(RW data),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(BSS)。 程序结束后有系统释放
通常代码段和只读数据段合成为文本段(Text), 包含实际要执行的代码(机器指令)和常量。它通常是共享的,多个实例之间共享文本段。文本段是不可修改的。
代码段由程序中执行的机器代码组成。在C语言中,程序语句进行编译后,形成机器代码。在执行程序的过程中,CPU的程序计数器指向代码段的每一条机器代码,并由处理器依次运行。
只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。
通常字符串常量就是放置在这里,程序结束后由系统释放。
注意:这个区域的存在与否,一直是一个争议的地方,但是我们这里认同是存在的,因为我们的程序中的确出现了与其他数据段不同的一块区域,但是往往很多时候大家把只读数据段(RO data)和下面的已初始化读写数据段(RW data)合成为数据段data,但是其实这个是不合适的,因为在执行过程中,这两个区域的读写权限是不同的,顾名思义,只读数据段(RO data)是只读的,而已初始化读写数据段是可读可写的。
已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并具有初值,以供程序运行时读写。
未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。
堆内存只在程序运行时出现,一般由程序员分配和释放。在具有操作系统的情况下,如果程序没有释放,操作系统可能在程序(例如一个进程)结束后回收内存。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
栈内存只在程序运行时出现,在函数内部使用的变量、函数的参数以及返回值将使用栈空间,栈空间由编译器自动分配和释放。其操作方式类似于数据结构中的栈。
代码段(Code)、只读数据段(RO data)、读写数据段(RW Data)、未初始化数据段(BSS)属于静态区域。
堆和栈属于动态区域。
代码段(Text)、只读数据段(RO data)和初始化读写数据段(RW data)在程序链接后即产生,存在与可执行文件中
C程序的内存布局(Memory Layout)-阿里云开发者社区
JVM之内存布局超详细整理 - 简书
Android内存管理分析总结 - 简书
(···条消息)C# 内存分配,CLR内存分配,.NET框架_写给自己看的博客-CSDN博客_c# 内存分配