前言:

国庆节的第三天,大家都回家了,一个人在宿舍好无聊。不过这年头与其说是出去玩不如是说出去挤,所以在学校里还是清闲的好。找工作不用担心了,到时候看着你们慢慢忙;插个话题,大学都没有恋爱过,总之各种原因了;大学毕业之后希望可以早点成家立业,不想一个人飘着了,所以看我笔记的人最好的是给我介绍女朋友了,PS非诚勿扰。

开始正题:之前学习了C++的内存管理,对于写程序有很大的帮助。最近在复习Java,虽然Java没有和C++那样复杂的内存操作,但是编写代码的时候还是要关注Java程序的内存管理知识。好的我们结合C/C++和Java的内存管理整理一下程序的内存管理。

1.首先看一下C++的一段代码:

char *a = "yang";  //  yang是保存在常量存储区的, a只是一个指针,a的内容是指向这个字符串的首地址。

char *b = "yang";// 同样 b也是一个指针,b的内容也是一个地址,指向在常量存储区的yang首地址。

cout << a << endl; // yang

cout << b << endl; // yang //输出这两个字符串,都是yang

// 我们看一下a,b 中的内容是什么,就是一个地址,指向yang的首地址 所以输出是一样的。同理之后的判断也就当然是a==b了。

printf("a=%d\n",a); // int 地址空间

printf("b=%d\n",b); // int 地址空间

if(a==b) {

cout << "a==b" << endl;  // a == b

}else{

cout << "a!=b" << endl;

}

C++的程序内存就先复习这么多,我们转入到Java

public static final String str0 = "yang";

// yang 这个字符串是保存在String Pool中的,str0也相当于一个地址,指向的是在内存中的yang的拷贝,之后所有在string pool 中的yang,如果不是new的字符串,那么访问的都是在内存中的String pool 的拷贝(如果你问我什么是String Pool,建议自己google一下);

public static void main(String[] args) {

// TODO Auto-generated method stub

final String str1 = "yang";

final String str2 = "yang";

String str4 = "yang";

String str5 = "yang";

// str1 str2 str4 str5 其实都是访问的在String Pool在内存中的拷贝的副本,也就是str1,str2, str4,str5 中保存的都是string pool 中的yang在内存中的同一个副本的地址。也就是当我们判断他们是否相等的时候,判断的是他们的指向的内存地址是不是相同,结果可想而知就是str0 == str1 == str2 == str4 ==str5

String str6 = new String("yang");//这一句就是在堆中创建一个新的字符串,其中yang任然是在String Pool中的那一个数据,但是我们在内存中(更具体的说是堆中)创建了一个新的yang的副本,我们的str6中保存的地址就是在新的副本中的地址,而不是之前的在栈中的地址。所以 直接比较他们是不相等的。

System.out.println(str0 == str1);

System.out.println(str1 == str2);

System.out.println(str4 == str5);

System.out.println(str1 == str4);

System.out.println(str0 == str6);

}

String Pool的知识好多同学都没有接触过,所以可能比较难以理解,如果真的想搞开发的话,尤其是后台开发,那么这个关于程序中的内存的知识还是十分重要的。(有点晕吧,初学的时候也是有点晕)

2.专心看一下Java程序的内存管理知识

在C++中的内存管理new/delete, malloc/free,这种方式创建的对象都是保存在堆中的,需要我们自己去管理这些内存的知识,所以会比较麻烦,其实自身感觉学习完C/C++内存管理之后,反倒是认为这种方式让我们更加明确程序的运行。而对于其他的数据存放在堆栈中的数据,当对象超出作用域的时候,就会自动销毁失效;还有一部分的数据是保存在用户存储区的,这部分的数据是在程序入口之前初初始化好的,然后再程序结束的时候才会去销毁的。

在看一下Java是如何管理内存的:首先是new 关键字,程序中使用new为每一个对象申请的内存空间(基本类型除外),所有的对象都是保存在堆中的(Heap),这些对象的释放是有GC决定和执行的,也就是我们程序员不用管这些在堆中的对象空间何时被释放,相对C++来说,省却了释放堆中对象内存的操作;Java中所有的内存释放都是GC完成的,内存的分配都是程序完成的,这样一进一出的内存管理方式简化了程序员的工作。但是这种方式加重了JVM的工作,一定程度上来说,这也造成了Java运行的速度低于C/C++的原因之一。因为GC为了能够正确释放对象的空间,GC必须监控每一个对象的运行状态,如对象的申请、引用、被引用、赋值等等操作,这些都是GC底层实现的。

监控每一个对象就是为了更加准确的、及时的释放掉对象的空间,而释放的原则就是该对象不会在被引用。

(PS:看起来好像省却了开发人员的工作,但是如果需要高性能的程序开发,还是必须掌握JVM底层的GC是如何回收内存空间的)

如何理解GC回收内存的机制?

可以这样理解:从程序开始的时候,所有的对象创建、引用、赋值等等都会看成一个有向图,从程序开始的地方,通过一些引用指向内存中的实际对象。如果一个对象在该程序的对象组成的有向图的中从根节点不可达,那么就会被GC 回收掉。

public static void main(String a[]){

Object obj1 = new Object();

Object obj2 = new Object();

obj1 = obj2;

//这个时候obj1就会被GC回收掉,而不用我们程序员亲自去释放掉这个对象在堆中的空间。

}

(图片引用其他网站上的,不是自己做的)

这种方式的释放堆中内存的精准地十分高,但是效率十分的低。

Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。

3.了解程序内存泄露的知识

C++中内存泄露的就是不会在使用的对象,在堆中一直存在,这样会造成内存的浪费;在Java中,对于那些不在会在使用到的对象,但是还是和有向图的根节点联通,对象无法被GC回收掉,造成程序的内存泄露。

虽然我们可以在程序中使用System.gc()回收内存空间,根据Java规范,并不一定会保障JVM执行垃圾回收。而且不同的JVM实现的gc是不同的。

看一段代码:

Vector<Object> v = new Vector<Object>();

for(int i = 0; i < 10; i++){

Object obj = new Object();

v.add(obj);

obj = null;

}

其实每一次循环中obj对象并没有被释放掉,因为我们将这些对象的引用放到Vector中了,所以对于我们删除掉obj对象,但是依然存在对堆中对象的引用,所以GC不会回收掉这个对象。

4.程序内存的4部分

程序启动的时候,有四大块内存空间:stack, heap, code, data segment

Heap segment:存储使用new声明的数据,在Java中,GC会自动回收,C++中需要程序员自己维护;

Stack Segment:存储局部变量的内存区域,当变量超出作用域的时候,就会自动释放掉该内存空间。

Code Segment:存储的是程序的函数;

Data Segment: 在程序开始的时候,静态变量存放在data segment中;

分析一段代码:

class Demo{

private int firistNum;

private int secondNum;

public static int temp = 3;

public Demo(int firstNum,int secondNum){

this.firstNum = firstNum;

this.secondNum = secondNum;

}

}

public class Test{

Public static void main(String [] args){

Demo test = new Demo(3,4);

}

}

首先在程序开始的时候,在data segment中存储的是静态变量 temp

然后进入程序中,在stack中有test, 然后就是 变量3,4进行拷贝到实参中 firstNum、secondNum,之后在Heap中有一个Demo的对象,释放掉stack中的firstNum secondNum,然后就是将Stack中的Demo对象的地址赋给stack中的test变量。

Java复习2.程序内存管理的更多相关文章

  1. C++复习12.程序内存管理

    程序内存管理 20131006 一个程序在运行期间的内存是如何的对编写程序至关重要,之前整理的C++内存管理的知识和Java程序内存管理的知识.今天我们系统的整理一下程序的内存. 1.一个程序的内存有 ...

  2. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  3. java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)

    概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...

  4. 深入理解Java虚拟机(自动内存管理机制)

    文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...

  5. zabbix3.0.4关于java服务端程序内存溢出的处理

    关于java服务端程序内存溢出的处理 java服务端程序内存溢出会产生jvm.log文件,此时程序会挂掉,无法正常处理业务,需要重启服务 思路: 当存在jvm.log这个文件的时候则触发clean_j ...

  6. C程序内存管理

    C程序的内存管理 熟悉Java语言的肯定知道,Java中内存管理是由虚拟机帮助我们完毕的,在C/C++中可不是这样,程序猿须要自己去分配和回收内存空间.本文记录了C程序可运行文件的存储结构.在内存中的 ...

  7. Java杂谈1——虚拟机内存管理与对象访问

    1.理解JAVA虚拟机的内存管理 运行时的数据区 从java虚拟机的内存分配来看,一个java程序运行时包含了如下几个数据区: a)     程序计数寄存器(Program Counter Regis ...

  8. 【深入理解Java虚拟机】自动内存管理机制——垃圾回收机制

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

  9. 【深入理解Java虚拟机】自动内存管理机制——内存区域划分

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

随机推荐

  1. Android开发学习之路--传感器之初体验

    说到传感器,还是有很多的,有加速度啊,光照啊,磁传感器等等.当然android手机之所以称为智能手机,少不了这几款传感器的功劳了.下面就学习下了,这里主要学习光照,加速度和磁. 新建工程emSenso ...

  2. iOS 屏幕方向

    参考文章:http://www.tuicool.com/articles/e2q6zi 一般的应用,只会支持竖屏正方向一个方向,支持多个屏幕方向的应用还是比较少的. 当时也没搞明白,所以直接就设置了正 ...

  3. div效果很好的遮盖层效果

    [html] view plaincopyprint? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&qu ...

  4. 可视化分析工具Cytoscape使用记录

    最近项目要使用到可视化分析工具Cytoscape,所以会花费很多的时间跟精力来整理Cytoscape软件使用和开发的相关资料,希望写下的文章能减少有兴趣的同行学习跟开发所走的弯路时间.同时也是因为百度 ...

  5. Oracle WorkFlow(工作流)(二)

    2.4消息(Message) 消息主要是为通知服务的,可以把消息当作通知的内容和类型.消息也属于一个单据类型,通知只能和同一个单据类型里的消息相关联. 每个消息可以有一个或多个属性和自己相联系,消息的 ...

  6. 【Unity Shaders】Reflecting Your World —— Unity3D中的遮罩反射(Masking Reflections)

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  7. WebLogic重启

     1,用户名密码登录. 2,切换到weblogic的bin目录下  cd bea/user_projects/domains/base_domain/bin/ 3,先停止服务器  ./stopWe ...

  8. sed-加速你在Linux的文件编辑

    1. Sed简介 sed是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为"模式空间"(pattern space),接着用sed命令处理缓冲区中 ...

  9. Dynamics CRM 2013 停用和激活按钮的显示与隐藏

    CRM中命令栏上的有些按钮是可以通过权限控制显示和隐藏的,比如新建.保存.保存并关闭.删除等,但惟独激活和停用无法控制,但我们还是可以用权限去控制,只是稍微绕了那么一下. 这里就要涉及到按钮的自定义了 ...

  10. shell的shift用法

    位置参数可以用shift命令左移.比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1.$2.$3丢弃,$0不移动.不带参数的shift命令相当于shift 1. 非常 ...