关于分布式程序 java的内存管理浅谈

关于分布式程序 java的内存管理浅谈

标签(空格分隔): 分布式 内存管理 java


Preface

当前全球正处于互联网时代,是个信息大爆炸时代。对于商家来说,每一天信息都是宝贵的,都可以转换成money的。所以对数据的处理要求也变的越来越严格,从以前的hadoop/MapReduce 的离线处理,到现在的准实时和实时处理,都是由数据需求而引起的技术革命。数据的处理快慢取决于很多因素。现在主流的解决方法,像Spark,Flink,Pular,包括腾讯,阿里,百度的诸多为开源的框架都是基于分布式内存的大数据处理计算框架,所以内存的使用变的很关键。由于各个框架都是基于JVM语言开发的,所以JVM的内存管理问题被提上日程。

Java AutoBoxing and UnBoxing

提到Java大家都会想到AutoBoxing和UnBoxing,这项技术最早是在jdk1.5引入进来的。AutoBoxing是java编译器的自动转换过程,针对primitive和与之对应的object wrapper类之间的自动转换,例如把int转换为Integer,double转换为Double等等。反之呐就是Unboxing。

虽然Boxing技术给开发人员带来了很多方便,但是也带来了问题——内存的问题

所有的primitive 的Object 类型都是继承于Object类的,如果调用new Object(), object没有任何其他可存储的成员,那么它也会占用8个字节的内存。

大家都知道C语言中字节是4字节对齐的,那么java也是字节对齐的,不过是8字节对齐的。类的成员变量声明的先后顺序也能影响该类所占的内存大小。

在现今的大数据处理时代,为了能够提高实时性,很多数据直接在内存中不落地的,所以内存占用很大,也会造成一定效率问题。

这个autoboxing的问题很早之前就已经有人提出来了,有个开源的lib叫fastutil是针对java的autoboxing和unboxing做了优化的。读者可以自行下载源码看看。

Programming based on Memory

上学时图书馆有本书貌似叫《Programming based on Limited Memory》,内容讲的是在移动设备上编程,很老的一本书,那个时候的移动设备内存最大才1M,一般都是512K居多,现在这个Programming based on Limited Memory概念仍然是需要的。

之前Spark提出来基于内存RDD的计算模式,在其documents上对于Memory Tuning有几条建议:

There are three considerations in tuning memory usage: the amount of memory used by your objects (you may want your entire dataset to fit in memory), the cost of accessing those objects, and the overhead of garbage collection (if you have high turnover in terms of objects).

By default, Java objects are fast to access, but can easily consume a factor of 2-5x more space than the “raw” data inside their fields. This is due to several reasons:

  • Each distinct Java object has an “object header”, which is about 16 bytes and contains information such as a pointer to its class. For an object with very little data in it (say one Int field), this can be bigger than the data.
  • Java Strings have about 40 bytes of overhead over the raw string data (since they store it in an array of Chars and keep extra data such as the length), and store each character as two bytes due to String’s internal usage of UTF-16 encoding. Thus a 10-character string can easily consume 60 bytes.
  • Common collection classes, such as HashMap and LinkedList, use linked data structures, where there is a “wrapper” object for each entry (e.g. Map.Entry). This object not only has a header, but also pointers (typically 8 bytes each) to the next object in the list.
  • Collections of primitive types often store them as “boxed” objects such as java.lang.Integer.

摘自Tuning Spark

还有一点关于In-Process Memory 和Distributed Memory的对比:

  1. Consistency

    • In-Process Memory: While using an in-process cache, your cache elements are local to a single instance of your application. Many medium-to-large applications, however, will not have a single application instance as they will most likely be load-balanced. In such a setting, you will end up with as many caches as your application instances, each having a different state resulting in inconsistency. State may however be eventually consistent as cached items time-out or are evicted from all cache instances.
    • Distributed caches, although deployed on a cluster of multiple nodes, offer a single logical view (and state) of the cache. In most cases, an object stored in a distributed cache cluster will reside on a single node in a distributed cache cluster. By means of a hashing algorithm, the cache engine can always determine on which node a particular key-value resides. Since there is always a single state of the cache cluster, it is never inconsistent.
    • Commnets If you are caching immutable objects, consistency ceases to be an issue. In such a case, an in-process cache is a better choice as many overheads typically associated with external distributed caches are simply not there. If your application is deployed on multiple nodes, you cache mutable objects and you want your reads to always be consistent rather than eventually consistent, a distributed cache is the way to go.

2.Overheads

  • In-Process Memory, This dated but very descriptive article describes how an in-process cache can negatively effect performance of an application with an embedded cache primarily due to garbage collection overheads. Your results however are heavily dependent on factors such as the size of the cache and how quickly objects are being evicted and timed-out.
  • Distributed caches, A distributed cache will have two major overheads that will make it slower than an in-process cache (but better than not caching at all): network latency and object serialization
  • Commnets , As described earlier, if you are looking for an always-consistent global cache state in a multi-node deployment, a distributed cache is what you are looking for (at the cost of performance that you may get from a local in-process cache).

3.Reliability

  • In-Process Memory, An in-process cache makes use of the same heap space as your program so one has to be careful when determining the upper limits of memory usage for the cache. If your program runs out of memory there is no easy way to recover from it.
  • Distributed caches,A distributed cache runs as an independent processes across multiple nodes and therefore failure of a single node does not result in a complete failure of the cache. As a result of a node failure, items that are no longer cached will make their way into surviving nodes on the next cache miss. Also in the case of distributed caches, the worst consequence of a complete cache failure should be degraded performance of the application as opposed to complete system failure.
  • Commnets, An in-process cache seems like a better option for a small and predictable number of frequently accessed, preferably immutable objects. For large, unpredictable volumes, you are better off with a distributed cache.

摘自 In-Process Caching vs. Distributed Caching

Open Project Solutions

  1. Apache Flink 利用Java的Unsafe API来自行管理程序内存

    详细请看 Juggling with Bits and Bytes,代码可以去github上去clone一下,关于内存管理这块在flink-runtime module里

  2. 开源的Lib,fastutil: http://fastutil.di.unimi.it/
  3. Facebook Presto: Slice(这是facebook利用github上的一个牛人开源项目) github
上述如有不对的地方还请指正,小弟将不胜感激。 转载请注明出处,谢谢

Reference

  1. Autoboxing and Unboxing
  2. Dalvik和Java字节码的对比
  3. 一个Java对象到底占多大内存?
  4. Java对象内存结构
  5. Facebook Presto presentation
  6. Presto 在美团
  7. Understanding Presto
  8. Presto Meetup @ Facebook (2014-05-14)
时间: 2024-11-09 20:29:51

关于分布式程序 java的内存管理浅谈的相关文章

iOS之内存管理浅谈

1.何为ARC ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release.在对象被创建时retain count+1,在对象被release时count-1,当count=0时,销毁对象.程序中加入autoreleasepool对象会由系统自动加 上autorelease方法,如果该对象引用计数为0,则销毁.那么ARC是为了解决MRC手动管理内存存在的一些而诞生的. MRC下内存管理的缺点: 释放一个堆内存时,首先要确定指向这

java自动内存管理机制

java程序员把内存管理的工作交给虚拟机,一旦出现内存泄露或者溢出问题,如果不了解内存是怎样工作的,那么排查错误将是一件异常艰难的工作. java内存区域与内存溢出异常 java运行时数据区域划分: 线程隔离的 1.程序计数器(Program Counter Register) 当前线程执行代码的行号指示器,当线程切换并分配处理器执行时间,为了保证线程恢复到正确的执行位置,每个线程都有独立的计数器 2.虚拟机栈(VM Stack) 虚拟机栈描述的是java方法执行的内存模型:每个方式执行的同时会

Java虚拟机内存管理机制

自动内存管理机制 Java虚拟机(JVM)在执行Java程序过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则是依赖用户线程的启动和结束而建立和销毁.根据<Java虚拟机规范 第2版>规定,运行时数据区包括: 1.程序计数器 一块较小的内存空间,不在Ram上,而是直接划分在CPU上的,程序员无法直接操作它.当前线程所执行的字节码的行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码指令.每条

JAVA当中内存管理与垃圾回收!

很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确实很低,一方面,Java语言采用面向对象思想,这也决定了其必然是开发效率高,执行效率低.另一方面,Java语言对程序员做了一个美好的承诺:程序员无需去管理内存,因为JVM有垃圾回收(GC),会去自动进行垃圾回收. 其实不然: 1.垃圾回收并不会按照程序员的要求,随时进行GC. 2.垃圾回收并不会及时

java的内存管理

Java程序运行在JVM(Java Virtual Machine,Java虚拟机)上,可以把JVM理解成Java程序和操作系统之间的桥梁,JVM实现了Java的平台无关性,由此可见JVM的重要 性.所以在学习Java内存分配原理的时候一定要牢记这一切都是在JVM中进行的,JVM是内存分配原理的基础与前提. 简单通俗的讲,一个完整的Java程序运行过程会涉及以下内存区域: l 寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制. l 栈:保存局部变量的值,包括:1.用来保存基本数据类型的

Java的内存管理与内存泄露

作为Internet最流行的编程语言之一,Java现正非常流行.我们的网络应用程序就主要采用Java语言开发,大体上分为客户端.服务器和数据库三个层次.在进入测试过程中,我们发现有一个程序模块系统内存和CPU资源消耗急剧增加,持续增长到出现java.lang.OutOfMemoryError为止.经过分析Java内存泄漏是破坏系统的主要因素.这里与大家分享我们在开发过程中遇到的Java内存泄漏的检测和处理解决过程. 本文先介绍Java的内存管理,以及导致Java内存泄露的原因. 一. Java是

关于java虚拟机内存管理的一些讲解

java数据类型: 1)原始类型:Primitive Types(原始值) 数值类型(Numeric Types) 整型类型(Integral Types),浮点类型(Floating-Point Types) 布尔类型(Boolean Types) returnAddress类型:表示一条字节码指令的操作码(Opcode).在所有的虚拟机支持的原始类型之中,只有 returnAddress 类型是不能直接 Java 语言的数据类型对应起来的. 2)引用类型:Reference Types(引用

黑马程序员-OC内存管理 @property的增强

涉及到内存管理,只读,多线程等很多功能时,setter和getter方法也就没那么简单了:当然@property依然强大,很好用: 1:内存管理相关参数: *:retain:  (如果是oc对象类型),生成的setter会自动release旧值,retain新值: *:assign:(适用于非oc对象)  这个是默认的值 *:copy:release旧值,copy新值: @property (retain) NSString *name; // 同类型的参数不能同时写 // @property

程序运行时内存管理

1,管理运行阶段内存空间分配 malloc()/new; int *pn = new int(存储的类型,内存根据此设定相应存储字节的内存) pn是内存地址(所以 当声明一个变量的指针变量时没初始化,声明后再来初始化则pn 接收的应该是变量在内存中的地址 &VariableName); *pn是存储在内存的值 用于给所指向内存中的变量赋值; 为一个数据对象(结构,基本类型)获得并指定分配内存格式 typeName pointer_name = new typeName; 指定需要什么样的内存和用