Java即将引入新对象类型来解决内存使用问题

目录
  • 一、Valhalla
  • 二、Java类型系统的不足
  • 三、对象头
  • 四、Value Class

前言:

2022年Java将有什么新的特性和改进,我相信很多Java开发者都想知道。结合Java语言架构师布莱恩·格茨Brian Goetz)最近的一些分享,

一、Valhalla

布莱恩·格茨在去年底发表了一篇名为State of Valhalla的文章,里面信息量非常大,里面提到早在2014年Java项目组就启动了一个名叫Valhalla的项目,这个项目将为JVM平台带来更加灵活的、扁平化的数据类型。在2021年该项目将有进一步的动作,值对象(value objects)原始类(primitive classes)专用泛型(specialized generics)即将引入JVM平台。今天先来聊聊这个值对象是个啥。

我们知道什么是“值”,什么是“对象”,但是什么是“值对象”呢?不光你们懵逼,我也懵逼,来一起研究研究。

二、Java类型系统的不足

Java类型系统由内置的10种类型组成,这10种类型无法直接表达复杂的数据结构,例如字符串、三维坐标、空间向量等等,但是开发者可以用这10种类型来为业务实体建模,Java的类型体系是非常有用的。

但是Java类型仍然存在“缺陷”, 同一个类的两个对象包含完全相同的属性,但是它们的内存寻址是不一样的。

所以从某种意义上说,他们有自己的身份标识。

但是对于原始类型就不一样了,如果一个int类型的变量值为7,另一个变量也为7,区分它们有意义吗?这个7还是那个7?显然是无意义的。

让我们再来举一个现实中的例子,两件相同尺寸、材质的红色衣服肯定是两件不同的衣服,但是它们的材质肯定是一种材质,颜色肯定是一种颜色,不会有傻子认为这是两种材质、两种颜色。这里面的尺寸可以通过Java中的原始类型去描述,但是材质和颜色不行(虽然颜色可以用十六进制表示),在这个场景里,尺寸、材质、颜色都应该被认为是一种原始属性,不应该具有标识,现在的Java显然不能直接满足这一点。

这个痛点促使了Valhalla项目的诞生。

三、对象头

为了理解Valhalla引入的 Value Class 概念能够给我们带来了什么,我们需要看看JVM是如何将对象保存在内存中的。

对象头对类的对象非常重要,决定哪个线程可以访问对象、垃圾收集器标记、对象hash;更重要的还有对象的类型指针,它能够在运行时动态访问对象的类,并从其类到该对象的详细信息,比如继承多态、反射。

但是凡事都有两面性,Java对象内存占用的大小取决于它所包含的信息的总和,对象头在 64 位系统上至少需要 16 个字节,在 32 位系统上至少需要 8 个字节(当然JVM可以通过配置项去设置如何保存对象头)。很多对象不需要多线程,也不需要什么对象标识,就像上面提到的衣服的颜色,只有颜色的值才是我们关心的事。这种冗余的内存占用让Java为人诟病。

四、Value Class

对于许多对象来说,它属性值的相等性是我们关心的,其它类信息没什么用,而且只为保存值和对这些值进行操作而编写的类在所有类中所占的比例非常大。Valhalla项目为这样的场景引入了一个新的类类型:Value Class。目前还只是JEP草案,但是已经初具形态:

value class Substring implements CharSequence {
    private String str;
    private int start;
    private int end;
    public Substring(String str, int start, int end) {
        checkBounds(start, end, str.length());
        this.str = str;
        this.start = start;
        this.end = end;
    }
    public int length() {
        return end - start;
    }
    public char charAt(int i) {
        checkBounds(0, i, length());
        return str.charAt(start + i);
    }
    public Substring subSequence(int s, int e) {
        checkBounds(s, e, length());
        return new Substring(str, start + s, start + e);
    }
    public String toString() {
        return str.substring(start, end);
    }
    private static void checkBounds(int start, int end, int length) {
        if (start < 0 || end < start || length < end)
            throw new IndexOutOfBoundsException();
    }
}

Value Class和我们常见的类差不多,但是它可能具有下面一些特性(这些依然在讨论中):

  • 值对象是没有身份的对象,通常情况下我们用==运算符检查身份,然而这里==可能和equals()不再有区别。
  • 值类本身和它的所有字段默认都是final的。
  • 该类不能直接或间接地实现java.lang.IdentityObject(有身份标识类的新超类)。这意味着超类要么是无状态抽象类,要么Object是无状态抽象类。
  • 值类都是java.lang.ValueObject的隐式实现。
  • 没有构造super函数调用构造函数。将在不执行任何超类初始化代码的情况下创建实例。
  • 无法在值类中使用synchronized关键字。
  • (可能)该类没有声明finalize()方法。
  • (可能)构造函数不使用this来设置构造函数主体中的字段,或者可能在所有字段都明确内存分配之后。

其它的操作和普通的类应该差别不大,但是要注意的是,JDK标准库中的一些原有类如果被认定为Value Class需要做兼容性处理。

value要成为保留字还是关键字?

这不是全部:

Value Class对Java类对象头进行了阉割,有利于降低Java的内存消耗,但这仅仅是Valhalla计划的一小部分。对于这一部分过于超前的内容,胖哥写起来其实是很有困难的,构思了好几天。从场景出发来了解一门编程语言的特性设计是非常有利于从根本提高自己的。如果你想了解更多关于Valhalla的东西,可以关注我,我会继续分享相关的知识。

到此这篇关于Java即将引入新对象类型来解决内存使用问题的文章就介绍到这了,更多相关Java 内存问题内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中使用内存映射实现大文件上传实例

    在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验. 复制代码 代码如下: package test; import java.io.BufferedInputStream;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import

  • Java虚拟机使用jvisualvm工具远程监控tomcat内存

    jdk中自带了很多工具可以用于性能分析,位于jdk的bin目录下,jvisualvm工具可以以图形化的方式更加直观的监控本地以及远程的java进程的内存占用,线程状态等信息. 一.配置tomcat 在tomcat的catalina.sh文件开头加上如下配置: JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=fa

  • Java内存缓存工具Guava LoadingCache使用解析

    这篇文章主要介绍了Java内存缓存工具Guava LoadingCache使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.Guava介绍 Guava是Google guava中的一个内存缓存模块,用于将数据缓存到JVM内存中.实际项目开发中经常将一些公共或者常用的数据缓存起来方便快速访问. Guava Cache是单个应用运行时的本地缓存.它不把数据存放到文件或外部服务器.如果不符合需求,可以选择Memcached.Redis等工具

  • macOS上使用gperftools定位Java内存泄漏问题及解决方案

    这几天在排查一个堆外内存泄漏的问题时看到很多人都提到了gperftools这个神器,想要尝试一下结果发现它对macOS的支持不太友好.而且大多数教程是针对C++的,里面的一通编译链接的操作看得我个Java仔眼花缭乱的.所以我在这里整理一份mac和Java版的使用教程,免得大家再来踩坑了. 一.简介 gperftools是google提供的一套分析工具,包括堆内存检测heap-profiler,内存泄漏分析工具heap-checker和CPU性能监测工具cpu-profiler.众所周知堆外内存的

  • java使用内存数据库ssdb的步骤

    看这篇文章的同学,redis相信你一定很熟悉了,ssdb是一个功能类似于redis,性能稍弱于redis的高性能数据库,主要是可以使用磁盘代替内存,使得小内存可以胜任请求不高的大部分场景,从而节约资源.ssdb官方是这样评价的 : 一个高性能的支持丰富数据结构的 NoSQL 数据库, 用于替代 Redis. 1. 特性 替代 Redis 数据库, Redis 的 100 倍容量 LevelDB 网络支持, 使用 C/C++ 开发 Redis API 兼容, 支持 Redis 客户端 适合存储集合

  • idea插件篇之java内存分析工具(JProfiler)的使用

    前言 在运行java的时候有时候想测试云运行时占用内存情况,这时候就需要使用测试工具查看了.在eclipse里面有 Eclipse Memory Analyzer tool(MAT)插件可以测试,而在idea中也有这么一个插件,就是JProfilerl. 下载安装 打开idea,进入设置界面 安装之后重启即可. 安装成功后查看情况. 这是什么情况呢,这是这个插件启动需要依赖一个可执行的文件,就是源生的JAVA PROFILER 去官网下载 https://www.ej-technologies.

  • 深入分析Java内存区域的使用详解

    Java 内存划分: 在Java内存分配中,java将内存分为:方法区,堆,虚拟机栈,本地方法栈,程序计数器.其中方法区和堆对于所有线程共享,而虚拟机栈和本地方法栈还有程序计数器对于线程隔离的.每个区域都有各自的创建和销毁时间. 程序计数器:     作用是当前线程所执行的字节吗的行号指示器.Java的多线程是通过线程轮流切换并分配处理器执行时间方式来实现的.因此,每个线程为了能在切换后能恢复到正确的位置,每个线程需要独立的程序计数器. Java 虚拟机栈: 每个放在被执行的时候都会同时创建一个

  • Java即将引入新对象类型来解决内存使用问题

    目录 一.Valhalla 二.Java类型系统的不足 三.对象头 四.Value Class 前言: 2022年Java将有什么新的特性和改进,我相信很多Java开发者都想知道.结合Java语言架构师布莱恩·格茨(Brian Goetz)最近的一些分享, 一.Valhalla 布莱恩·格茨在去年底发表了一篇名为State of Valhalla的文章,里面信息量非常大,里面提到早在2014年Java项目组就启动了一个名叫Valhalla的项目,这个项目将为JVM平台带来更加灵活的.扁平化的数据

  • Java redis存Map对象类型数据的实现

    目录 背景描述 实体类 父类 子类 方法1° 方法2° 背景描述 项目需要将设备采集到的最新经纬度信息存入redis缓存中,方便及时查询检索.考虑到根据检索条件不同,所查询的设备不同.采取将数据以map类型存入redis缓存,在此记录一下. 实体类 注:一定要实现序列化接口 父类 public class Redis implements Serializable{     private String name;     private Integer age;     public Stri

  • Java序列化JSON丢失精度问题的解决方法(修复Long类型太长)

    目录 原因: 解决办法一: 解决办法(二): 总结 Java序列化JSON时long型数值,会出现精度丢失的问题. 原因: java中得long能表示的范围比js中number大,也就意味着部分数值在js中存不下(变成不准确的值). 解决办法一: 使用ToStringSerializer的注解,让系统序列化时,保留相关精度 @JsonSerialize(using=ToStringSerializer.class) private Long createdBy; 上述方法需要在每个对象都配上该注

  • Java对象类型的判断详解

    instanceof 判断某个对象是否是某个类的实例或者某个类的子类的实例.它的判断方式大概是这样的: public<T> boolean function(Object obj, Class<T> calzz) { if (obj == null) { return false; } try { T t = (T) obj; return true; } catch (ClassCastException e) { return false; } } Class.equals()

  • 解决feignClient调用时获取返回对象类型匹配的问题

    feignClient调用时获取返回对象类型匹配 feignClient是springCloud体系中重要的一个组件,用于微服务之间的相互调用,底层为httpClient,在之前的应用中,我一直以为A服务提供的方法返回类型为对象的话,那么调用A服务的B服务必须也用字段类型以及命名完全相同的对象来接收,为此我验证了一下,发现不是必须用完全相同的对象来接收,比如,可以用map<String,Object>或者Object来接收,然后解析. 当然,复杂对象我还是推荐用一个完全相同的对象来接收. 下面

  • 带你入门Java的类与对象

    目录 类和对象 类的属性 成员方法 形参和实参 局部变量 可变参数 构造方法 this关键字 this.属性名 this.方法名 static关键字 静态变量 1)静态变量 2)实例变量 静态方法 静态代码块 对象的创建 显式创建对象 方法隐含创建对象 总结 匿名对象 总结 类和对象 在面向对象中,类和对象是最基本.最重要的组成单元.类实际上是表示一个客观世界某类群体的一些基本特征抽象.对象就是表示一个个具体的东西.所以说类是对象的抽象,对象是类的具体. "人类"只是一个抽象的概念,它

  • Java语法关于泛型与类型擦除的分析

    泛型与类型擦除 泛型,JDK 1.5新特性,本质是参数化类型(Parametersized Type) 的应用,即所操作的数据类型被指定为一个参数.这种参数类型可用在: 类 接口 方法 的创建中, 分别称为: 泛型类 泛型接口 泛型方法 在Java还没有泛型的版本时.只能通过: Object 是所有类型的父类 类型强制转换 两个特性协作实现类型泛化.例如,在哈希表的存取中,JDK 1.5之前使用HashMap的get() 方法,返回值就是个Object.由于Java语言里面所有的类型都维承于ja

  • 学习Java九大内置对象

    本文实例为大家介绍了Java九大内置对象,供大家参考,具体内容如下 1.Request对象 该对象封装了用户提交的信息,通过调用该对象相应的方法可以获取封装的信息,即使用该对象可以获取用户提交的信息. 当Request对象获取客户提交的汉字字符时,会出现乱码问题,必须进行特殊处理.首先,将获取的 字符串用ISO-8859-1进行编码,并将编码存发岛一个字节数组中,然后再将这个数组转化为字符串对象 即可.如下: String textContent=request.getParameter("bo

  • java教学笔记之对象的创建与销毁

    本课程的目标是帮你更有效的使用Java.其中讨论了一些高级主题,包括对象的创建.并发.序列化.反射以及其他高级特性.本课程将为你的精通Java的旅程提供指导. 1. 引言 在TIOBE 编程语言排名中,Sun 公司于1995年开发的Java语言是世界上使用最广泛的编程语言之一.作为一种通用编程语言,因为强大的工具包和运行时环境.简单的语法.丰富的平台支持(一次编写,到处运行)以及的异常活跃的社区支持,Java语言对软件开发工程师极具吸引力. 在这一系列的文章中,涵盖了Java相关的高级内容,因此

  • java Spring 5 新特性函数式Web框架详细介绍

    java Spring 5 新特性函数式Web框架 举例 我们先从示例应用程序的一些摘录开始.下面是暴露Person对象的响应信息库.很类似于传统的,非响应信息库,只不过它返回Flux<Person>而传统的返回List<Person>,以及返回Mono<Person>的地方返回Person.Mono<Void>用作完成标识:指出何时保存被完成. public interface PersonRepository { Mono<Person> g

随机推荐