返回顶部
首页 > 资讯 > 精选 >如何在Java项目中创建一个内存区域与对象
  • 327
分享到

如何在Java项目中创建一个内存区域与对象

javaava目中 2023-05-31 08:05:06 327人浏览 薄情痞子
摘要

本篇文章给大家分享的是有关如何在Java项目中创建一个内存区域与对象,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、java内存区域Java虚拟机在执行Java程序的过程中会

本篇文章给大家分享的是有关如何在Java项目中创建一个内存区域与对象,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

一、java内存区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范(JavaSE7版)》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域。

1.程序计数器(线程私有)

程序计数器(Program Counter ReGISter)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时 就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

每条线程都有一个独立的程序计数器,各个线程之间互不影响,独立储存。

如果线程正在执行的是一个java方法,计数器记录的是正在执行的虚拟机字节码指令的地址;

如果线程正在执行的是一个Native方法,计数器值为空(undefined)。

此内存区域是唯一一个在Java规范中没有规定任何OutOfMemoryError(OOM)情况的区域

2.Java虚拟机栈(线程私有)

虚拟机栈(Java Virtual Machine Stacks)描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程。

通常大家所说的虚拟机堆内存和栈内存中,栈内存一般是指这里的局部变量表部分。

局部变量表存放了编译期可知的各种基本数据类型、对象引用(不是对象本身,可能是指向对象的指针或代表对象的句柄或其他的与此对象相关的位置,涉及到下文的“对象的访问定位”)和returnAddress类型。

3.本地方法栈(线程私有)

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,区别不过是虚拟机栈为Java方法(字节码)所服务,而本地方法栈则为虚拟机使用的Native方法服务。Java虚拟机规范没有对本地方法栈使用的语言、方式和数据结构有强制规定。因此虚拟机可以自由实现它,甚至有的虚拟机直接把本地方法栈和虚拟机栈合二为一。

4.Java堆(线程共享)

Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。唯一的目的就是存放对象实例。所有的对象实例和数组都要在堆上分配内存。

Java堆是垃圾收集器管理的主要区域。Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,类似于磁盘空间。在实现时既可以是固定大小,也可以是可扩展的,当前的主流虚拟机都是按照可扩展实现的。如果在堆中没有内存完成实例化分配,并且堆也无法扩展时,会抛出OOM异常。

5.方法区(线程共享)

方法区(Method Area)用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

虚拟机规范把方法区描述为了堆的一个逻辑部分,但有个别名Non-Heap。

6.运行时常量池(线程共享) 

运行时常量池(Runtime Constant Pool) 是方法区的一部分。

class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容在类加载后进入方法区的运行时常量池中保存。 

Java虚拟机对Class文件中的每一部分的格式都有严格的规定。每一个字节用于存储哪种数据都必须符合规范才会被虚拟机认可、装载和执行,但是对于运行常量池,Java虚拟机规范没有做任何细节的要求,不同的虚拟机可以按照自己的需求进行实现。不过,一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。

运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定要只有编译的时候产生,运行期间也可能将新的常量放入池中,利用的多的便是String类的intern()方法。

在无法再申请到内存是会排除OOM异常。

二、HotSpot虚拟机对象探秘

HotSpot虚拟机在Java堆中对象分配、布局和访问过程的探讨。

1.对象的创建

Java是面向对象的语言,在程序的执行过程中随时都有可能会有对象被创建,从语言层面上讲,创建对象(例如克隆,反序列化)通常仅仅是new关键字。

过程:

加载类:当虚拟机遇到一个new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且通过检查这个符号引代表的类是否已经被加载、解析和初始化过。如果没有则执行相应的类加载过程。(此处不讨论这部分的具体内容,详情参考第七章)

分配内存:在类加载通过后,虚拟机要为新生对象分配内存,对象所需要的内存在类加载后就可以确定,为对象分配空间就是从Java堆中划分出来。此时常见有两种方法:(1)指针碰撞:若堆中内存是绝对规整的,已经使用的在一边,没有使用的在一边,中间有个分割指针,则只需要把分割指针向没有使用的内存移动所需要的固定大小(2)空闲列表:Java堆内存不是规整的,已使用的未使用的是相互交错的,虚拟机就要维护一个列表,列表保存哪些是已经使用的,哪些是未被使用的,分配的时候只需要从未被使用的内存中分配固定的大小给新对象。

选择哪种方法由堆内存是否规整所决定,而是否规整取决于采用的垃圾收集器是否带有压缩整理功能。

可以很明显的看出,这种分配空间的方法不是线程安全的,可能在对A对象分配时指针还没来得及修改,对象B就采用了原来的指针,解决这个问题有两种方案:

 (1)对分配空间的动作进行同步化处理:实际上虚拟机采用CAS配上失败重试的方式保持更新操作的原子性(要么全部做完,要么一点也不做)。

 (2)把内存分配的动作按照线程划分在不同的空间上进行,即每个线程在Java堆中预先分配一块内存,成为本地线程分配缓冲TLAB。哪个线程要分配内存就在那个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时才需要同步定。

内存空间初始化:内存分配结束后,虚拟机将分配的内存空间都初始化为零值(不包括对象头,分配的内存空间的具体内容下一部分会解释),如果使用TLAB来完成,这一工作可以提前到TLAB分配时进行,这一操作保证了对象的实例字段在Java中不赋初始值就可以直接使用,即零值。

对象头设置:接下来,虚拟机要对对象进行必要的设置,例如:是哪个类的实例?如何找到类的元数据信息?哈希码?对象的GC分代年龄等。这些信息存放在对象的对象头(Object Header)中。

初始化:从虚拟机视角来看,一个新的对象已经产生,但是从Java程序来看,这才刚刚开始,因为内存的数据内容都是零值,执行new之后,会执行<init>方法,按照程序员的要求来进行初始化。

2.对象的内存布局

分为三部分:

(1)对象头

 ①存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。32位虚拟机中为32bit,64位虚拟机中为64bit,官方称之为"Mark Word"。但是需要的存储的运行时数据太多,其实已经超过了32bit或者64bit,但是对象头信息是与对象自身定义的数据无关的额外存储成本,考虑到虚拟机的效率Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态来复用自己的存储空间。例如在32位的HotSpot虚拟机中,如果对象处于未被锁的状态下,那么就不储存和锁有关的信息,25bit存储hashcode,4bit存储GC,2bit存储锁标志位、1bit固定为0。

 ②类型指针,即对象指向他的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的示例。并不是所有的虚拟机实现都必须通过数据上保留类型指针(和对象的访问定定位有关,下面会进行解释)。如果对象是一个Java数组,那在对象头还必须有一块来记录数组长度的数据,因为从数组的元数据中无法确定数组的大小。 

(2)实例数据

对象真正存储的有效信息,也是程序代码中所定义的各种类型的字段内容,无论是父类继承下来的还是子类中定义的,都要记录下来。这部分的存储顺序会受到虚拟机分配策略参数(FieldAllocationStyle)和字段在Java源码中定义的顺序有关。HotSpot虚拟机默认的分配策略为: longs/doubles、ints、shorts/chars、bytes/booleans、oop(Ordinary Object Pointers),从策略中可以看出,相同宽度的字段总是被分配到一起。在满足这个的前提下,在父类中定义的变量会出现在子类之前。如果CompactFields参数值为true(默认就是true),那么子类之中较窄的变量也可能插入到父类变量的空隙之中。

(3)对齐填充

 不是必然存在的,也没有特殊的含义,仅仅是占位符的作用。由于HotSpot VM 的自动内存管理必须要求对象的起始地址必须是8字节的整数倍,换句话说就是对象的内存大小必须是8字节的整数倍,如果不足,则填充到8的整数倍。

3.对象的访问定位

即栈内存中的引用如何访问堆内存中的对象。目前主流的方式有两种:

(1)使用句柄:Java堆中会划分一块区域作为句柄池,栈中存储的就是对象的句柄地址,而句柄中包含了对象实例数据指针(指向堆内存中)和类型数据指针(指向方法区)。

(2)直接指针:栈中存储的直接就是对象地址,而堆中对象的布局要包括对象示例数据和类型数据指针(指向方法区)。

使用句柄的优点: 引用中存储的稳定的句柄地址,在对象移动(垃圾收集时移动对象是非常普遍的行为),只会改变句柄的实例数据指针,而引用本身不会改变。

直接指针的优点: 速度快,节省了一次指针定位的时间开销。由于对象访问十分频繁,极少成多之后也是可观的执行成本。HotSpot虚拟机是使用第二种进行对象访问的。

以上就是如何在Java项目中创建一个内存区域与对象,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网精选频道。

--结束END--

本文标题: 如何在Java项目中创建一个内存区域与对象

本文链接: https://lsjlt.com/news/224583.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何在Java项目中创建一个内存区域与对象
    本篇文章给大家分享的是有关如何在Java项目中创建一个内存区域与对象,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、java内存区域Java虚拟机在执行Java程序的过程中会...
    99+
    2023-05-31
    java ava 目中
  • 内部类对象如何在Java项目中创建
    这篇文章给大家介绍内部类对象如何在Java项目中创建,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java创建内部类对象实例详解要想使用new生成一个内部类的实例,需要先指向一个外部类的实例,也就是先生成外部类的实例,...
    99+
    2023-05-31
    java 内部类对象 ava
  • 如何在java中创建一个对象
    这篇文章给大家介绍如何在java中创建一个对象,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序。1、创建对...
    99+
    2023-06-14
  • eclipse中如何创建一个java项目
    在Eclipse中创建一个Java项目非常简单。请按照以下步骤操作: 打开Eclipse,并确保已经安装了Java开发工具包(JD...
    99+
    2024-04-02
  • 怎么在java中创建一个对象
    这篇文章给大家介绍怎么在java中创建一个对象,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. 网页开发;5. ...
    99+
    2023-06-14
  • 如何在Java中创建一个String字符串对象
    这篇文章将为大家详细讲解有关如何在Java中创建一个String字符串对象,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java中字符串对象创建有两种形式,一种为字面量形式,如String ...
    99+
    2023-05-31
    java string 字符串
  • 如何在pycharm中创建一个新项目
    如何在pycharm中创建一个新项目?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。操作环境:windows7系统、PyCharm 4.0.3版,DELL G3电脑。pychar...
    99+
    2023-06-07
  • 如何在eclipse中创建一个spring boot项目
    这期内容当中小编将会给大家带来有关如何在eclipse中创建一个spring boot项目,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。spring Boot是由Pivotal团队提供的全新框架,其设计目...
    99+
    2023-05-31
    eclipse springboot spring boo
  • 如何在Android项目中创建一个选项菜单
    这期内容当中小编将会给大家带来有关如何在Android项目中创建一个选项菜单,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。使用OptionMenu只要重写两个方法public boolean onCrea...
    99+
    2023-05-31
    android roi 目中
  • 怎么在java中创建一个对象数组
    这篇文章给大家介绍怎么在java中创建一个对象数组,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程序;2. 面向对象;3. 分布性,Ja...
    99+
    2023-06-14
  • 如何Android项目中创建一个View
    这篇文章将为大家详细讲解有关如何Android项目中创建一个View,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。从布局文件到LayoutParams首先从Activity的setConte...
    99+
    2023-05-31
    android view roi
  • 怎么在java中创建一个内存布局
    本篇文章给大家分享的是有关怎么在java中创建一个内存布局,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java可以用来干什么Java主要应用于:1. web开发;2. And...
    99+
    2023-06-14
  • java循环中创建对象内存溢出如何解决
    在Java循环中创建对象可能导致内存溢出的主要原因是对象持有的内存没有被及时释放。为了解决这个问题,可以考虑以下几种方法:1. 确保...
    99+
    2023-10-10
    java
  • 如何在IDEA中利用maven创建一个springMVC项目
    如何在IDEA中利用maven创建一个springMVC项目?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、DEA创建项目 新建一个maven project,并且...
    99+
    2023-05-31
    maven springmvc idea
  • eclipse中如何创建第一个tomcat项目
    要在Eclipse中创建第一个Tomcat项目,请按照以下步骤操作:1. 打开Eclipse并选择“File”菜单,然后选择“New...
    99+
    2023-09-27
    eclipse tomcat
  • 如何在 Go 中创建一个共享内存的 Goroutine?
    可以通过 channel 实现共享内存的 goroutine:创建一个 channel 以指定元素类型。启动一个 goroutine 向 channel 写入数据。在主 goroutin...
    99+
    2024-05-16
    共享内存
  • 如何在Bash中创建Java的Path对象?
    在Bash中创建Java的Path对象可能是Java开发人员经常需要处理的任务之一。Path对象是Java中表示文件路径的一种方式,而Bash则是一种常用的Unix shell。 在Bash中创建Java的Path对象,我们需要使用Java...
    99+
    2023-09-21
    path 对象 bash
  • 在eclipse中如何创建第一个javaweb项目并运行
    这篇文章主要介绍“在eclipse中如何创建第一个javaweb项目并运行”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“在eclipse中如何创建第一个javaweb项目并运行”文章能帮助大家解决问...
    99+
    2023-07-05
  • 如何在Android项目中创建一个自定义控件
    本篇文章为大家展示了如何在Android项目中创建一个自定义控件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。仿iPhone 的风格,在界面的顶部放置一个标题栏。<&#63;xml v...
    99+
    2023-05-31
    android roi 目中
  • 如何在idea中创建一个SpringBoot项目(超详细教学)
    如何在idea中创建一个SpringBoot项目 目录 环境准备 1.1打开IDEA,点击New新建一个项目 1.2 使用Spring Initializr方式构建Spring Boot项目  1.3 设置项目所属组,项目名称,选择java...
    99+
    2023-09-02
    intellij-idea spring boot java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作