成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

哪個更快:Java堆還是本地內存

開發 后端
在這篇文章中,我會給你演示一個對象是怎樣以連續的字節碼的方式在內存中進行存儲,并且告訴你是應該怎樣存儲這些字節,是在Java堆中還是在本地內存中。最后我會就怎樣從JVM中訪問內存更快給一些結論:是用Java堆還是本地內存。

使用Java的一個好處就是你可以不用親自來管理內存的分配和釋放。當你用new關鍵字來實例化一個對象時,它所需的內存會自動的在Java堆中分配。堆會被垃圾回收器進行管理,并且它會在對象超出作用域時進行內存回收。但是在JVM中有一個‘后門’可以讓你訪問不在堆中的本地內存(native memory)。在這篇文章中,我會給你演示一個對象是怎樣以連續的字節碼的方式在內存中進行存儲,并且告訴你是應該怎樣存儲這些字節,是在Java堆中還是在本地內存中。最后我會就怎樣從JVM中訪問內存更快給一些結論:是用Java堆還是本地內存。

[[179275]]

使用Unsafe來分配和回收內存

sun.misc.Unsafe可以讓你在Java中分配和回收本地內存,就像C語言中的mallocfree。通過它分配的內存不在Java堆中,并且不受垃圾回收器的管理,因此在它被使用完的時候你需要自己來負責釋放和回收。下面是我寫的一個使用Unsafe來管理本地內存的一個工具類:

 

  1. public class Direct implements Memory { 
  2.  
  3.     private static Unsafe unsafe; 
  4.     private static boolean AVAILABLE = false
  5.  
  6.     static { 
  7.         try { 
  8.             Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe)field.get(null); AVAILABLE = true; } catch(Exception e) { // NOOP: throw exception later when allocating memory } } public static boolean isAvailable() { return AVAILABLE; } private static Direct INSTANCE = null; public static Memory getInstance() { if (INSTANCE == null) { INSTANCE = new Direct(); } return INSTANCE; } private Direct() { } @Override public long alloc(long size) { if (!AVAILABLE) { throw new IllegalStateException("sun.misc.Unsafe is not accessible!"); } return unsafe.allocateMemory(size); } @Override public void free(long address) { unsafe.freeMemory(address); } @Override public final long getLong(long address) { return unsafe.getLong(address); } @Override public final void putLong(long address, long value) { unsafe.putLong(address, value); } @Override public final int getInt(long address) { return unsafe.getInt(address); } @Override public final void putInt(long address, int value) { 
  9.         unsafe.putInt(address, value); 
  10.     } 

在本地內存中分配一個對象

讓我們來將下面的Java對象放到本地內存中:

 

  1. public class SomeObject { 
  2.  
  3.     private long someLong; 
  4.     private int someInt; 
  5.  
  6.     public long getSomeLong() { 
  7.         return someLong; 
  8.     } 
  9.     public void setSomeLong(long someLong) { 
  10.         this.someLong = someLong; 
  11.     } 
  12.     public int getSomeInt() { 
  13.         return someInt; 
  14.     } 
  15.     public void setSomeInt(int someInt) { 
  16.         this.someInt = someInt; 
  17.     } 

我們所做的僅僅是把對象的屬性放入到Memory中:

 

  1. public class SomeMemoryObject { 
  2.  
  3.     private final static int someLong_OFFSET = 0
  4.     private final static int someInt_OFFSET = 8
  5.     private final static int SIZE = 8 + 4// one long + one int 
  6.  
  7.     private long address; 
  8.     private final Memory memory; 
  9.  
  10.     public SomeMemoryObject(Memory memory) { 
  11.         this.memory = memory; 
  12.         this.address = memory.alloc(SIZE); 
  13.     } 
  14.  
  15.     @Override 
  16.     public void finalize() { 
  17.         memory.free(address); 
  18.     } 
  19.  
  20.     public final void setSomeLong(long someLong) { 
  21.         memory.putLong(address + someLong_OFFSET, someLong); 
  22.     } 
  23.  
  24.     public final long getSomeLong() { 
  25.         return memory.getLong(address + someLong_OFFSET); 
  26.     } 
  27.  
  28.     public final void setSomeInt(int someInt) { 
  29.         memory.putInt(address + someInt_OFFSET, someInt); 
  30.     } 
  31.  
  32.     public final int getSomeInt() { 
  33.         return memory.getInt(address + someInt_OFFSET); 
  34.     } 

現在我們來看看對兩個數組的讀寫性能:其中一個含有數百萬的SomeObject對象,另外一個含有數百萬的SomeMemoryObject對象。

// with JIT:
Number of Objects:  1,000     1,000,000     10,000,000    60,000,000
Heap Avg Write:      107         2.30          2.51         2.58      
Native Avg Write:    305         6.65          5.94         5.26
Heap Avg Read:       61          0.31          0.28         0.28
Native Avg Read:     309         3.50          2.96         2.16

// without JIT: (-Xint)
Number of Objects:  1,000     1,000,000     10,000,000    60,000,000
Heap Avg Write:      104         107           105         102      
Native Avg Write:    292         293           300         297
Heap Avg Read:       59          63            60          58
Native Avg Read:     297         298           302         299

結論:跨越JVM的屏障來讀本地內存大約會比直接讀Java堆中的內存慢10倍,而對于寫操作會慢大約2倍。但是需要注意的是,由于每一個SomeMemoryObject對象所管理的本地內存空間都是獨立的,因此讀寫操作都不是連續的。那么我們接下來就來對比下讀寫連續的內存空間的性能。

訪問一大塊的連續內存空間

這個測試分別在堆中和一大塊連續本地內存中包含了相同的測試數據。然后我們來做多次的讀寫操作看看哪個更快。并且我們會做一些隨機地址的訪問來對比結果。

// with JIT and sequential access:
Number of Objects:  1,000     1,000,000     1,000,000,000
Heap Avg Write:      12          0.34           0.35
Native Avg Write:    102         0.71           0.69
Heap Avg Read:       12          0.29           0.28
Native Avg Read:     110         0.32           0.32

// without JIT and sequential access: (-Xint)
Number of Objects:  1,000     1,000,000      10,000,000
Heap Avg Write:      8           8              8
Native Avg Write:    91          92             94
Heap Avg Read:       10          10             10
Native Avg Read:     91          90             94

// with JIT and random access:
Number of Objects:  1,000     1,000,000     1,000,000,000
Heap Avg Write:      61          1.01           1.12
Native Avg Write:    151         0.89           0.90
Heap Avg Read:       59          0.89           0.92
Native Avg Read:     156         0.78           0.84

// without JIT and random access: (-Xint)
Number of Objects:  1,000     1,000,000      10,000,000
Heap Avg Write:      55          55              55
Native Avg Write:    141         142             140
Heap Avg Read:       55          55              55
Native Avg Read:     138         140             138

結論:在做連續訪問的時候,Java堆內存通常都比本地內存要快。對于隨機地址訪問,堆內存僅僅比本地內存慢一點點,并且是針對大塊連續數據的時候,而且沒有慢很多。

最后的結論

在Java中使用本地內存有它的意義,比如當你要操作大塊的數據時(>2G)并且不想使用垃圾回收器(GC)的時候。從延遲的角度來說,直接訪問本地內存不會比訪問Java堆快。這個結論其實是有道理的,因為跨越JVM屏障肯定是有開銷的。這樣的結論對使用本地還是堆的ByteBuffer同樣適用。使用本地ByteBuffer的速度提升不在于訪問這些內存,而是它可以直接與操作系統提供的本地IO進行操作。

責任編輯:張燕妮 來源: Keep going
相關推薦

2018-04-17 14:41:41

Java堆內存溢出

2022-03-16 08:39:19

StackHeap內存

2022-08-27 14:42:45

Java集合數組

2012-02-20 11:33:29

Java

2021-11-07 14:37:59

列表編碼扁平化

2016-08-09 09:26:17

云計算

2009-06-03 15:52:34

堆內存棧內存Java內存分配

2022-09-07 11:52:48

forforEach前端

2021-03-08 09:00:00

Java編程內存

2021-12-13 09:26:31

JS代碼前端

2023-11-01 08:07:42

.NETC#

2020-05-09 13:49:00

內存空間垃圾

2019-12-12 11:19:33

JVM內存線程

2012-11-12 14:47:09

2015-08-06 14:54:50

JavaScript分析工具OneHeap

2022-12-26 14:41:38

Linux內存

2025-06-03 04:00:05

glibc堆內存Linux

2012-06-13 01:53:23

Java代碼

2019-02-26 14:33:22

JVM內存虛擬機

2025-01-21 07:39:04

Linux堆內存Golang
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九综合九九 | 狼色网| 欧美精品影院 | 免费视频一区二区三区在线观看 | 福利片在线观看 | av在线播放不卡 | 在线三级电影 | 澳门永久av免费网站 | 九九热在线视频观看这里只有精品 | 99精品电影 | 欧洲精品码一区二区三区免费看 | 午夜影院在线观看 | 青青草一区| 午夜影院 | 欧美一级电影免费观看 | www.99re5.com| 在线不卡| 日韩免费激情视频 | 最新黄色在线观看 | 伊人精品在线视频 | 怡红院免费的全部视频 | 日日做夜夜爽毛片麻豆 | 久久亚洲欧美日韩精品专区 | 最新超碰 | 乱一性一乱一交一视频a∨ 色爱av | 国产91网站在线观看 | 亚洲看片网站 | av激情在线 | av黄色在线 | 日韩三级 | 中文字幕成人在线 | 中文在线日韩 | 日韩蜜桃视频 | 精精久久 | 天天干天天干 | 超碰高清 | 日本不卡一区二区三区在线观看 | 亚洲福利在线观看 | 91国产在线播放 | 中文字幕在线观看 | 亚洲精品福利视频 |