博客出自:http://blog.csdn.net/liuxian13183,转载注明出处! All Rights Reserved !

下文是博主感悟,请带着怀疑性的态度阅读!

需要了解基本变量所占内存大小,请移步:读书笔记-类结构的认识

Java存储空间有这么几块-来源于Java编程思想

寄存器:位于处理器内部,不受外层代码控制,由处理器自行分配-C/C++可以建议分配方式

堆栈:位于RAM中  引用和基本数据类型存放的区块。 指针向下生成新对象,向上释放对象(new关键字),相当于链表结构。

堆:位于RAM中 对象存放的区块

常量存储:位于ROM中 存放于方法体中

非RAM存储:流对象和持久化数据-存储到硬盘

说到存储就难免讲到JVM的垃圾回收机制,需要了解的同学可以点进去看看

如果要实现处理器的高效率,那么就要压榨它的每一寸(byte)的运行能力,I3的处理器达到3.4GHz,即每秒运算3.4亿次,因此给它划分任务块,每块分配足够多的任务,实现高并发;所以对内存的模型需要详细了解。

由于硬件的读写速度与处理器的运算速度差距过大,一般都会写一层高速缓存来作为缓冲,一边从硬盘读数据到缓存,一边把处理器的处理结果写入缓存,一边把缓存中要写入的数据写到硬盘;因此很多程序会使用到中间件。

如果多个处理器同时处理缓存,就需要拟定协议谁先谁后,对于同一个处理器中的任务也是同样如此,有sychronzied关键字来处理;同时处理器还会对一段程序丧心病狂的进行(OOOE)乱序处理,也就是顺序在前面的代码并不一定先执行,对于依赖前段程序结果的代码来说,就需要通过其他途径来保证顺序性。

内存模型定义的关键在于第一使各处理器的操作不具有歧义 第二不影响拓展各自的特性;它主要定义虚拟机存取数据的细节,定义所有变量都存储在主内存,每条线程都有自己的工作内存(主内存的副本,或者叫引用),不同线程的工作内存互不直接访问,通过主内存来影响各自对值的引用;拿虚拟机来做例子,寄存器、栈、堆缓存就像工作内存,硬件设备就是主内存。

定义了八种操作来完成上述存取过程

lock和unlock 作用于主内存,标识为某线程独占或释放,成对存在

read和load 读取和加载,从主内存将数据读给工作内存,再加载到工作内存,成对存在

use和assign 使用和赋值 作用于工作内存,将变量给工作引擎,将接收到的值进行处理 成对存在

store和write 存储和写入 从工作内存将数据存回主内存,再写入主内存 成对存在

顺序过程unlock放到write后面即可。不允许读不入工作内存,也不允许写不入主内存;新变量只能在主内存中产生,不能跳级执行,lock与unlock一样重复执行多次,只是每次lock工作内存则被清空。lock可类比为Java的Lock对象。

讲完上面的存取过程,变量的原子性就很好讲了,原子性指对变量的存取过程顺序执行,要么执行完,要么不执行,不允许其他线程对其进行污染。而带有特殊含义的sychronzied和final关键字,就可以用原子性来解释:前者由于保障了unlock之前变量已同步到主内存,这里的变量指方法体或类中所有的;后者是避免构造器把this引用传递出去,因而像惰性气体一样稳定。

另外java的先行发生原则,很有意思,有以下几种表现形式

1、程序控制流顺序执行,即代码顺序执行

2、volitale和锁顺序执行,即前一个锁执行结束,后一个得到锁

3、Thread的start方法先于run方法内的方法执行

4、通过isAlive、interrupt和join方法判断线程是否存活

5、对象结束先于finilize方法执行

6、A先于B,B先于C,可得出A先于C执行的传递性。

最后再讲下volatile关键字,它有两个作用

1、保证改变后马上通知其他线程(执行write操作后,变量马上刷新),即对其他线程的可见性

2、保障上面所指丧心病狂的处理器处理此变量不被乱序操作,即禁止指令重排优化

但是volatile没有原子性(PS:原子性指read-assign-store这3组,只要一个执行,就会全部执行),不能保证作为计数器而正确存在;所以一般如果很少对它标识的变量进行改变的场景比较适用,比如多条线程共同执行多个有父类的任务,一个条件通知结束,则所有线程一起结束;就像劳动节来临,不论工程师还是设计师,都可以休息一天。

补充一点,64位的long和double无原子性,会被当成两个32位变量来处理,但一般默认为具有原子性,占用两个局部变量的位置

虚拟机运行时的数据区域有以下几种

虚拟机栈 主要存放引用和基本数据类型

堆 主要存放对象

方法区 常见的类信息除对象以外的所有,包括类信息(数据类型),常量池,方法、接口、静态变量等

本地方法栈 用来执行native方法

程序计数器 存储下一条需要执行的字节码指令,每条线程都有一个

虚拟机的多线程是通过线程切换并分配执行时间,同时一个内核在任一时刻只处理一条线程的指令

虚拟机栈和堆是线程共享的数据区,方法区、本地方法栈和程序计数器是线程所不能访问到的数据区

其中数据访问的方式有两种:一种是句柄形式,引用指向句柄,句柄包含对象地址和对象类型;一种是指针,直接存储对象地址,以句柄少一步,所以访问也会快一些,而HotSpot就是用这种;前者也有一定优化,值发生改变时,引用不用变,后者要改变指针才行。

内存异常有两种表现,一种叫OutOfMemoryError(内存溢出),请求的虚拟机扩展栈已无足够空间,分配给新对象,典型的标记-清理算法容易产品这种情况,另一种叫StackOverflowError(内存泄露),请求的栈深度超过虚拟机所允许 ,例如下标超过数据大小,一般线程不同步会引起这种状况的产生。

接下来对中英文分别占多少字节进行解释

public static void main(String[] args) {
String[] charsetNames = { "utf-8", "utf-16", "UTF-16BE", "UTF-16LE", "UTF-32", "UTF-32BE", "UTF-32LE", "unicode", "GBK", "GB2312", "GB18030",
"ISO8859-1", "BIG5", "ASCII" };

for (int i = 0; i < charsetNames.length; i++) {
printByteLength(charsetNames[i]);
}
}

/**
public static void printByteLength(String charsetName) {
* String类的不带参数的getBytes()方法会以程序所运行平台的默认编码方式为准来进行转换,
* 在不同环境下可能会有不同的结果,因此建议使用指定编码方式的getBytes(String charsetName)方法。
*/
String a = "a"; // 一个英文字符
String b = "啊"; // 一个中文字符
try {
System.out.println();
System.out.println(charsetName + "编码英文字符所占字节数:" + a.getBytes(charsetName).length);
System.out.println(charsetName + "编码中文字符所占字节数:" + b.getBytes(charsetName).length);
} catch (UnsupportedEncodingException e) {
System.out.println("非法编码格式!");
}
}

utf-8编码英文字符所占字节数:1
utf-8编码中文字符所占字节数:3 utf-16编码英文字符所占字节数:4
utf-16编码中文字符所占字节数:4 UTF-16BE编码英文字符所占字节数:2
UTF-16BE编码中文字符所占字节数:2 UTF-16LE编码英文字符所占字节数:2
UTF-16LE编码中文字符所占字节数:2 UTF-32编码英文字符所占字节数:4
UTF-32编码中文字符所占字节数:4 UTF-32BE编码英文字符所占字节数:4
UTF-32BE编码中文字符所占字节数:4 UTF-32LE编码英文字符所占字节数:4
UTF-32LE编码中文字符所占字节数:4 unicode编码英文字符所占字节数:4
unicode编码中文字符所占字节数:4 GBK编码英文字符所占字节数:1
GBK编码中文字符所占字节数:2 GB2312编码英文字符所占字节数:1
GB2312编码中文字符所占字节数:2 GB18030编码英文字符所占字节数:1
GB18030编码中文字符所占字节数:2 ISO8859-1编码英文字符所占字节数:1
ISO8859-1编码中文字符所占字节数:1 BIG5编码英文字符所占字节数:1
BIG5编码中文字符所占字节数:2 ASCII编码英文字符所占字节数:1
ASCII编码中文字符所占字节数:1

Linux默认可以存放100个进程,放1个跟99个是一样的,其他均为sleep状态,意思是已经开辟这么大内存,用还是不用,反正都在那里放着,不会浪费CPU时间,因此后台进程只要不是说一直处于活动状态,跟IOS一样,无需杀死后台进程。

String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); // 字符串的话是可以直接相等,跟int等其他数据类型一样
System.out.println(str1.equals(str2)); // 字符串的话是可以直接相等,跟int等其他数据类型一样

String strObj1 = new String("hello");
String strObj2 = new String("hello");
System.out.println(strObj1 == strObj2);// 值不等
System.out.println(strObj1.equals(strObj2));// 对象相等,因为char全相等

执行结果:

true
true
false
true

分析:拿String作为例子,其他容器类同样类似

    public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

首先判断是否是同一个对象,即两个引用指向同一个对象,那自然相等;

其次比较是否是同一种类型,如不等则返回false,如相等则继续;

最后比较内部的值,String的char,List的value,Map的key和value,如果完全相等则相等。

Java高级之内存模型分析的更多相关文章

  1. Java内存模型分析

    在学习Java内存模型之前,先了解一下线程通信机制. 1.线程通信机制 在并发编程中,线程之间相互交换信息就是线程通信.目前有两种机制:内存共享与消息传递. 1.1.共享内存 Java采用的就是共享内 ...

  2. 关于JAVA中的static方法、并发问题以及JAVA运行时内存模型

    一.前言 最近在工作上用到了一个静态方法,跟同事交流的时候,被一个问题给问倒了,只怪基础不扎实... 问题大致是这样的,“在多线程环境下,静态方法中的局部变量会不会被其它线程给污染掉?”: 我当时的想 ...

  3. Java对象的内存模型(一)

    前言 新人一枚,刚刚入门编程不久,各方面都在学习当中,博文有什么错误的地方,希望我们可以多多交流! 最近,在开发App后台过程中,需要将项目部署到云服务器上.而云服务器的内存大小却只有1G.要如何做到 ...

  4. Java虚拟机:内存模型详解

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实 ...

  5. java虚拟机的内存模型

    一.为什么要了解java虚拟机的内存模型 java虚拟机作为java代码运行的平台,是java技术的基石.了解java虚拟机的内存模型也就变得十分必要.它能帮助我们更好的了解java代码的运行机制,更 ...

  6. java内存模型分析2

    不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程.主内存和工作内存的交互关系如下图所示,和上图很类似. 这里的主内存.工作内存与Java内存区域的Java堆. ...

  7. Java虚拟机—Java8内存模型(整理版)

    1.概述 对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要手动释放内存,不容易出现内存泄露和内存溢出问题.一旦出现内存泄露和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,排查错误 ...

  8. 深入理解JAVA虚拟机(内存模型+GC算法+JVM调优)

    目录 1.Java虚拟机内存模型 1.1 程序计数器 1.2 Java虚拟机栈 局部变量 1.3 本地方法栈 1.4 Java堆 1.5 方法区(永久区.元空间) 附图 2.JVM内存分配参数 2.1 ...

  9. 深度解析Java多线程的内存模型

    内部java内存模型 硬件层面的内存模型 Java内存模型和硬件内存模型的联系 共享对象的可见性 资源竞速 Java内存模型很好的说明了JVM是如何在内存里工作的,JVM可以理解为java执行的一个操 ...

随机推荐

  1. 远程连接Kali Linux使用PuTTY实现SSH远程连接

    远程连接Kali Linux使用PuTTY实现SSH远程连接 本书主要以在Android设备上安装的Kali Linux操作系统为主,介绍基于Bash Shell渗透测试.由于在默认情况下,在Andr ...

  2. 模拟 Codeforces Round #249 (Div. 2) C. Cardiogram

    题目地址:http://codeforces.com/contest/435/problem/C /* 题意:给一组公式,一组数据,计算得到一系列的坐标点,画出折线图:) 模拟题:蛮恶心的,不过也简单 ...

  3. 如何在 .Net Framework 4.0 项目上使用 OData?

    最新的 Microsoft ASP.NET Web API 2.1 OData 5.1.0 已只能在 .Net Framework 4.5 的安装了,如果要在 VS2010的 .Net Framewo ...

  4. BZOJ3461 : Jry的时间表

    fl[i]表示[1,i]操作一次,且在[j+1,i]处操作的最大值 1:把[j+1,i]改为b[i]: max(sum[j]+b[i]*(i-j)) =b[i]*i+max(-j*b[i]+sum[j ...

  5. System call in linux by C

    1: #include <stdlib.h> 2: int system(const char *command); 3:  4: while (something) { 5: int r ...

  6. TYVJ P1094 矩形分割 标签:DP

    做题记录:2016-08-12 21:42:21 背景 YHOI Train#4 Problem 1 描述 出于某些方面的需求,我们要把一块N×M的木板切成一个个1×1的小方块.对于一块木板,我们只能 ...

  7. TYVJ P1034 尼克的任务 Label:倒推dp

    背景 题库靠大家,人人都爱它. 描述 尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成.尼克的一个工作 ...

  8. div里嵌套了img底部会有白块问题和图片一像素问题解决

    div里嵌套了img底部会有白块 因为img默认是按基线(baseline)对齐的.对比一下图片和右边的p, q, y等字母,你会发现这三个字母的“小尾巴”和图片下方的空白一样高.下面这张图中的黑线就 ...

  9. Metronic_下拉列表Select2插件的使用

    这个插件是基于Select的扩展插件,能够提供更加丰富的功能和用户体验,它的github官网地址为:https://select2.github.io/,具体的使用案例,可以参考地址:https:// ...

  10. HttpClient_HttpClient 对 cookie的处理

    session的保持是通过cookie来维持的,所以如果用户有勾选X天内免登录,这个session 就X天内一直有效,就是通过这个cookie来维护.如果没选X天内免登录,基本上就本次才能保持sess ...