[java]我的数据在哪里?——数据的内存模型
在编写程序时,我们也许会有这样一个问题,我们编写的程序中的数据运行时,会保存在哪里呢?简单直接的回答可能是——内存。这个回答在多数情况下可能都是对的,但事实上并不准确,我们都知道内存,即随机访问存储器可以在程序运行时保存程序所需要的数据,但不是所有数据,而且,内存这个词也并不准确。接下来,让我们看一下在程序运行时,数据可能会被存放的几大位置。
数据的六大存放位置
java为我们提供了不同于以往语言的新特性,其中一个非常方便的特性就是我们在创建新的类型(对象)时不需要手动分配内存,更不需要手动去销毁不再需要的对象,java让我们远离了对内存的繁琐操作。但是,在我们编写java程序时,依然需要做到对程序运行时数据的存放位置做到心中有数,这其中包括了寄存器、内存以及持久化存储。实际上,程序会使用到的数据,可能分配在以下六个位置:
(1) 寄存器。这是最快的保存区域,因为它是位于处理器内部,它的地理优势决定了存取都非常迅速。但是,寄存器的大小十分有限,所以它是根据编译器来分配的,我们没有直接分配的权利。也就是说,在java中,我们无法直接决定将哪些数据存放在寄存器中,也无法从程序中分析哪些数据可能会被存放在寄存器中。
图1 CPU
(2) 堆栈。这是存取速度次快的位置,它驻留于常规RAM(随机访问存储器)区域,也就是我们常说的内存。我们都知道,栈是一种常用的数据结构,而在内存的堆栈区域,它的数据保存方式就是按照栈的方式进行存取,我们可以通过它的“堆栈指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。创建程序时,Java 编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,想象一下,在我们创建对象时,很多字段都是动态创建的,所以尽管有些Java数据要保存在堆栈里——特别是对象引用,但实际的对象并不放到其中。
图2 栈
(3) 堆。一种常规用途的内存池(也在RAM 区域),java对象都会保存在该位置。我们都知道,“堆”同时也是一个基本的数据结构,它是一种特殊的完全二叉树,分为大顶堆和小顶堆,堆在满足一定的存取效率的基础上,提高了查找效率。和堆栈不同,堆是牺牲了存储效率获取了灵活性,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,这也是java对象之所以放置在堆中的原因。进一步讲,正是因为我们有了堆这个结构,java才能够做到方便的创建对象以及创建对象时动态的创建对象的字段。要求创建一个对象时,只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!所以在程序的编写中,我们要尽量避免频繁的创建对象,这会大大降低程序运行的时间。
图3 大顶堆
(4) 静态存储。这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM 里)。程序运行期间,静态存储的数据将随时等候调用。我们知道,static可以用来修饰一个字段或者方法是属于一个类的,这个时候static修饰的字段就是静态的,因为它在整个的程序运行过程中都是大小已知的。程序中的常量也存放在这里。
(5) 常数存储。常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。
(6) 非RAM 存储。若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器,比如说网络通信的数据。而对于固定对象,对象保存在磁盘中,比如说图片、数据库中的数据。即使程序中止运行,它们仍可保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中,比如说采用数据库管理响应的数据。一旦需要,能将它们恢复成普通的、基于RAM 的对象。
常见的数据存放位置示例
接下来,我们来看一下在编写程序中我们经常用到的数据,掌握他们的存放位置,会让我们在编写程序时更加得心应手,更好的把握程序耗费的时间。
在上面的六大存储地点中,寄存器是我们无法直接去控制的,非RAM存储一般会交由其他第三方去控制,因此在这里,我们主要探究剩下的几种方式。
首先我们来看下面的代码:
public class Person { public static final double PI = 3.14;
private String name = "dotgua"; public static void main(String[] args) {
int i = 5;
double d = 0.2;
Person p = new Person();
String str = new String("hello");
String str2 = "world";
}
}
上面这段代码比较短,但是涵盖了我们通常使用的大部分情景。
- 首先,i是main方法中的局部变量,所以i的值会保存在main的方法栈中(如图所示),除了整型,其他的局部变量,同时是基本类型(boolean/char/double/float等)的都会保存在堆栈中。
- 然后,p本身是引用类型,引用类型本身也会保存在堆栈中,而p中存放的是它指向的对象的地址(‘#####’部分)。
- p指向的Person对象会保存在堆中,任何通过new产生的对象都会放置在堆中,对象的成员属性和对象一起存放。请注意,Person类中的PI不会随对象一起存放,因为它本身由static修饰,所以是类成员,会被放置在静态存储中,这里如果有多个Person对象,那么这些对象都会指向同一个PI。
- 最后,比较有意思的是String类型,如果String是通过new产生的,那么它会和普通的对象一样存放在堆中。而如果是通过字符串字面量声明的,那么,字面量会存放在静态存储中(字面量本身是不会改变的),通过str2引用指向它。字符串放在静态存储中可以方便复用,因为字符串本身是不会改变的,所以如果有多个字符串声明的值相同,其实他们指向的是同一个字符串。这里对于字符串有个小技巧,对于通过new创建的字符串,我们可以使用String类的intern()方法将它重新放置在静态存储中。
总结
在java中,程序运行时,可能存放的位置大致有以下六个,分别是:
- 寄存器:位于CPU,速度最快,无法控制;
- 堆栈:内存RAM的一部分,用于存放局部变量;
- 堆:RAM中的一部分,通过new创建的对象都放在堆中,效率较低;
- 静态存储:类成员以及常量存放在这里,一般变化较小;
- 常数存储:常数值会直接存放在程序代码中;
- 非RAM存储:其他存储方式,不放置在内存中;
字符串通过new方式创建时会存放在堆中,通过字面量创建会存放在静态存储部分,可以通过String类的intern方法将new创建的字符串重新放置在静态存储中。
[java]我的数据在哪里?——数据的内存模型的更多相关文章
- 《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before
第16章 Java内存模型 终于看到这本书的最后一章了,嘿嘿,以后把这本书的英文版再翻翻.这本书中尽可能回避了java内存模型(JMM)的底层细节,而将重点放在一些高层设计问题,例如安全发布,同步策略 ...
- JVM运行时数据区与JVM堆内存模型小结
前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 ...
- Java虚拟机学习(1):体系结构 内存模型
一:Java技术体系模块图 Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆", 它用于存储虚拟机加载的类信息.常量.静态 ...
- 深入理解java虚拟机学习笔记(一)JVM内存模型
上周末搬家后,家里的宽带一直没弄好,跟电信客服反映了N遍了终于约了个师傅明天早上来迁移宽带,可以结束一个多星期没网的痛苦日子了.这段时间也是各种忙,都一个星期没更新博客了,再不写之前那种状态和激情都要 ...
- Java内存模型深度解析:总结--转
原文地址:http://www.codeceo.com/article/java-memory-7.html 处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会 ...
- 浅析java内存模型--JMM(Java Memory Model)
在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...
- java内存模型-总结
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM 和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM 和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照 ...
- Java锁(一)之内存模型
想要了解Java锁机制.引发的线程安全问题以及数据一致性问题,有必要了解内存模型,机理机制了解清楚了,这些问题也就应声而解了. 一.主内存和工作内存 Java内存模型分为主内存和工作内存,所有的变量都 ...
- 深入理解Java内存模型(七)——总结
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...
- 【转】深入理解Java内存模型(七)——总结
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...
随机推荐
- Oracle学习——第一章
Oracle数据库特点:安全性高,数据类型丰富 Oracle是由美国甲骨文公司开发的一款数据库产品 -------------------------------------------------- ...
- @RemoteProxy()注释 与@File注释的使用
@RemoteProxy()注释 dwr3.0可以通过全注解的方式,极大的简化了配置,所有xml配置加在一起不超过20行,而且使用更加简单,bean注入的问题也都解决.配置步骤如下: web.xml的 ...
- ABP框架系列之十二:(Audit-Logging-审计日志)
Introduction Wikipedia: "An audit trail (also called audit log) is a security-relevant chronolo ...
- 软件推荐-c#绘图插件echart
首先给出官网:http://echarts.baidu.com/examples/ 简单的教程:http://www.cnblogs.com/youmeng/p/4874897.html
- 后台获取url里面加密的参数中,特殊符号+获取到后端后是 一个空格的解决方法
进行加密,加密后的参数中有个+号: 前端的url:http://mtest.cmread.com:8145/nap/p/QRcode.jsp?activityId=11206&vcode=O/ ...
- UVaLive 4064 Magnetic Train Tracks (极角排序)
题意:给定 n 个不三点共线的点,然后问你能组成多少锐角或者直角三角形. 析:可以反过来求,求有多少个钝角三角形,然后再用总的减去,直接求肯定会超时,但是可以枚举每个点,以该点为钝角的那个顶点,然后再 ...
- 14.2.4HTML5约束API验证
<body> <form> <!-- required属性在提交表单时不能空着 这个属性适用于<input> <textarea> <sel ...
- python_day1 条件语句
一 流程控制 1.if....else 语句 用法: if 条件: 满足条件执行代码 else: if 条件不满足执行此部分代码 例: a = 10 b = 20 if a>b : pri ...
- 整理python小爬虫
编码使我快乐!!! 我也不知道为什么,遇到自己喜欢的事情,就越想做下去,可以一个月不出门,但是不能一天没有电脑 掌握程度:对python有了一个更清晰的认识,自动化运维,也许可以用python实现呢, ...
- EF6 学习笔记(二):操练 CRUD 增删改查
EF6学习笔记总目录 ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 接上篇: EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作 本篇原文链接: I ...