JVM内存结构和Java数据类型

Java是一门面向对象编程语言,由Sun公司于20世纪90年代开发,后来被Oracle公司收购,此语言不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。
也正是因为Java的语言的跨平台,适合网络编程,易用,健壮,稳定和智能(GC),以及强大的生态,又加上近几年移动开发的兴起,而在移动开发领域占据80%市场的Android系统主要是基于Java语言开发,才让这门仅仅诞生20年的语言成功蝉联高级开发语言排行榜的王座数年之久,直至笔者写这篇文章之时,Java还是处在Tiobe开发语言排行榜榜首。当然这一切JVM功不可没,本文将从虚拟机的角度切入,阐述Java的数据类型。
一、什么是JVM
 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因,通常本文所讲的虚拟机指代Oracle官方的”HotSpot虚拟机“。
所以从本质上来讲,Java也是一种解释型语言,由Java源程序编译成Class二进制流文件,然后由虚拟机JIT引擎动态编译成目标机器的机器语言执行。
二、什么时候需要JVM
所有的Java程序都依赖JVM执行,当Java程序运行时,JVM通过main方法作为程序的入口,依次加载Class文件解析执行,并分配一个独立的JVM内存空间。
三、在什么地方安装JVM
所有需要执行Java程序的设备都需要安装JRE。
JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。
JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
四、JVM的内存分配模型
通常大家都习惯把JVM的内存分为三个区域:堆区、栈区、方法区。下面我将为各位详细的说明各个内存区域所承担的职责:
1 、方法区。
方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息(class info)、常量(constant)、静态变量(static 修饰的变量)、即时编译器(JIT)编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫Non-Heap(非堆),目的应该是为了跟Java堆区分别开来。
2 、堆区。
Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所以的对象实例以及数组都要在堆上分配内存,但是随着JIT编译器的发展和逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上并不那么绝对了。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称作“GC堆”。
3 、栈区。
Java虚拟机栈(Java vcirtual Machine Stacks)也线程私有的,它的生命周期和线程一样。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(stack frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
4 、本地方法栈。
本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到Native方法服务。在虚拟机规范中对本地方法栈中方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的 虚拟机(譬如Sun HotSpot)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会跑出Stack Overflow 和 OutOfMemoryError异常。
5 、程序计数器。
程序计数器(Program Counter Register )是一块较小的内存空间,他可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型中(仅仅是概念模型,各种虚拟机的实现可能回通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理。线程恢复等基础功能都需要依赖这个计数器来完成。
当然JVM的内存模型不仅仅只包含这几块,还有常量池(包含在方法区)等。
从上述内存模型,我们也大概知道线程的安全模型问题,例如典型栈区是线程不共享的,相对线程安全,其他区线程不一定线程安全,当然Java也提供一系列的机制来保证线程安全。
Java 的数据类型
在讲Java数据类型之前先科普一下我们经常在开发中表达内存容量大小的单位:位 (bit)、字节(byte),字符(char)
通常一个“标准字符”是 1字节 = 8位 ,为什么叫标准字符呢?因为计算机科学最初是由西方世界发展起来的,他们的语言中最小单元就是一个英文字母也就是一个字符,所以就定义成一个字节存一个字符,当然随着计算机科学的发展,发现一个字节根本存不下其他语种的最小符号,例如汉字,所以就有了“标准字符”的说法。
一 、 Java基本数据类型
byte :占用 8 位存储空间,最大存储的数据量是255,存放的数据范围是-128~127之间 。
short :占用16位存储空间,最大存储的数据量是65536,数据范围是-32768~32767之间 。
int : 占用32位存储空间,最大存储的数据量是2的32次方-1,数据范围是-2的32次方~2的32次方-1 。
long :  占用64位存储空间,最大存储的数据量是2的64次方-1,数据范围是-2的64次方~2的64次方-1 。
float : 占用32位存储空间,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。
double :  占用64位存储空间,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
boolean : 占用一位储存空间, 只有true和false两个取值。
char : 占用16位存储空间,存储Unicode码,用单引号表示。

注意:在Java中浮点类型默认是double的,即2.00和1.10在计算机里转换进行二进制存储,这就涉及到数据精度,出现这个现象的原因正式浮点型数据的精度问题。所以通常我们不用float和double类型进行比较,对于精度要求较高的商业系统,我们通常使用BigDecimal对象来进行表示。

float a = 2.00 - 1.10  打印的结果不是期待的0.9 ,而是 0.8999999 。
要想正常打印: 必须在数字后面加个 f 。
二 、Java 引用类型
String :用双引号表示,存储字符串。

Array : 数组类型。

Object : 对象类型。
等 。。。 当然引用类型又包含,强引用,弱引用,虚引用,本文就不再阐述了,感兴趣的同学自行查阅相关资料。
很多人说Java的参数传递既有值传递,又有引用传递其实是不对的,我们都知道Java是没有的指针的说法,Java的栈区存放对象的内存地址,所以我们如果用
System.print.out(); 打印对象的话,通常控制台打印的是一串看不懂的hash 码,如果要打印对象信息只能通过调用对象的toString()的方法进行打印 。在Java里面只有值传递,对于基本数据类型,方法的形参传递的是实参值,对于引用类型,传递的是实参的内存地址,所以很多同学就误以为Java 既有值传递又有引用传递 。


发布了15 篇原创文章 · 获赞 15 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/a568418299/article/details/78884060