오프힙 외부 메모리에 대해 모르십니까? 어레인지~

콘텐츠

  • 온힙 온힙 메모리란 무엇입니까?
  • JVM 힙 메모리는 어떻게 분할되나요?
  • JVM 힙 메모리가 가득 차면 어떻게 됩니까?
  • 오프 힙 메모리를 기반으로 시스템 GC 중단 문제 해결

오늘은 아주 흥미로운 지식, 즉 오프힙 오프힙 메모리에 대해 이야기하겠습니다. 인터뷰를 하러 가거나 어떤 기술을 연구할 때 오프힙 오프 힙 메모리를 자주 접할 수 있지만 많은 사람들이 오프힙(off-heap) 오프힙(off-heap) 메모리가 정확히 무엇인지, 그래서 오늘은 깊이 있는 분석을 해드리겠습니다.

온힙 온힙 메모리란 무엇입니까?

오프 힙 오프 힙 메모리 에 대해 이야기하려면 먼저 온 힙이 온 힙 메모리라고 말해야 합니다 . 많은 사람들이 이 온 힙 온 힙 메모리, 즉 자바 시스템에 익숙해야 한다고 생각합니다. 우리는 일반적으로 실제로 실행을 작성합니다. JVM 프로세스입니다. 이 JVM 프로세스에는 전용 메모리 공간이 있습니다. 이 메모리 공간은 힙에 있는 메모리이며, 대략 다음 그림과 같습니다.

JVM 힙 메모리는 어떻게 분할되나요?

그렇다면 여기서 일반적으로 어떤 문제가 발생합니까? 일반적으로 말하면 큰 문제는 없으나 JVM 힙 메모리에 캐싱된 데이터 양이 많으면 문제가 생길 수 있는데 이른바 데이터 캐쉬 라고 하는 것은 힙 메모리 에 많은 양의 데이터가 저장되는 것을 의미한다 . 데이터는 항상 사용되어야 하므로 일반적으로 재활용이 불가능하므로 다음 그림과 같이 JVM의 힙 메모리에 많은 데이터가 남게 된다.

이미지.png

그러면 다음 질문이 나오는데, 이 JVM의 힙 메모리가 나누어져 있는데, 한 영역은 젊은 세대 , 다른 영역은 구세대 처럼 캐시된 데이터는 힙 메모리에 오랫동안 존재하기 때문에 일반적으로 일정 시간 동안 세대에 머물다가 가비지 수집이 불가능하기 때문에 아래 그림과 같이 구세대에 배치됩니다.

이미지.png

JVM 힙 메모리가 가득 차면 어떻게 됩니까?

但是这个老年代里如果放了太多缓存数据以后,就可能会导致他剩余的可用空间就会比较少了,此时可能会导致老年代经常会放一点别的数据就塞满了,一旦塞满了就会触发JVM的full gc,有一个垃圾回收线程会去回收老年代里的数据,此时如下图。

可是此时一般来说能回收的也就是除了缓存数据之外的一些空间,哪怕你回收了,但是缓存数据是要一直存在的,所以没法回收掉,此时会导致每次你回收了一部分剩余空间之后,然后还是剩余了很多缓存数据,此时对于缓存数据来说会一直占据老年代的很大空间

那么此时必然导致一个现象,那就是老年代会频繁的写一点数据就满了,写一点数据就满了,然后一会儿就得触发一下full gc,一会儿就得触发一下full gc,每次full gc都会导致JVM停止运行,没法处理外部请求,此时对外部来说,就会感觉你的系统性能经常抖动,一会卡一下,一会儿卡一下。

所以往往来说,把很多数据缓存在JVM内部,是很可能导致上述现象,就是老年代频繁塞满、频繁触发fullgc、频繁导致系统停顿没法处理请求,如下图。

이미지.png

基于堆外内存解决系统gc卡顿问题

所以针对这种情况,往往我们的优化手段,就是会把要缓存的数据,从JVM堆内存里转移到offheap堆外内存里去,那所以问题来了,啥叫做堆外内存呢?就是顾名思义,不归JVM管的内存区域,os操作系统负责管理的一部分内存,叫做堆外内存

따라서 실제로 많은 데이터를 오프 힙 메모리에 직접 쓰는 것을 선택할 수 있습니다.이 경우 JVM 힙에서 이전 세대의 공간을 차지하지 않으며 이전 세대가 자주 채워지지 않습니다. 풀 gc를 자주 트리거하므로 다음 그림과 같이 시스템 성능이 자주 지터(jitter)됩니다.

이미지.png

이 오프 힙 메모리가 너무 좋기 때문에 문제는 어떤 단점이 있습니까? 물론 JVM 힙에 있는 메모리를 사용한다면 많은 양의 데이터를 작성한 후 메모리가 가득 차면 이 때 JVM이 자동으로 가비지 콜렉션을 수행하여 일부 메모리 공간을 확보할 수 있도록 도와주기 때문에 완전히 자동.

하지만 off-heap 메모리를 사용한다면 이를 관리해주는 JVM이 없기 때문에 이 때 그 메모리 공간을 스스로 관리해야 하는 것 즉, 데이터를 작성한 후 필요할 때 직접 관리해야 한다. 메모리의 일부를 해제하는 데 주의하십시오. 그러면 오프 힙 메모리로 인해 JVM이 자주 gc되지는 않지만 아래 그림과 같이 코드 관리가 더 어려워 질 수 있습니다.

이미지.png

그렇다면 일반적으로 자바 코드에서 이 오프힙 메모리를 어떻게 적용할까요? 아래 코드를 보시면 일반적으로 netty나 rockmq와 같은 미들웨어 는 많은 양의 메모리 데이터를 관리해야 하기 때문에 오프힙 메모리를 신청해서 그 안에 데이터를 집어넣는 방식을 선택하여 자체적으로 세분화된 관리를 하게 됩니다. .

// 定义好要申请的堆外内存的大小,这里是1GB
int memorySize = 1024 * 1024 * 1024;
// 用Java里的ByteBuffer.allocateDirect方法就可以申请一块堆外内存
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(memorySize);
// 把数据写入到堆外内存里去
byte[] bytes = "hello world".getBytes();
byteBuffer.put(bytes);
// 从堆外内存里读取数据
byteBuffer.flip();
byte[] readBytes = new byte[bytes.length];
byteBuffer.get(readBytes, 0, bytes.length);
复制代码

이 코드를 통해 오프 힙 메모리를 적용하는 방법과 오프 힙 메모리에서 데이터를 쓰고 읽는 방법을 본 후 이제 오프 힙 메모리를 해제하는 방법에 대해 생각합니까? 이 경우 오프 힙 메모리는 실제로 JVM 힙의 ByteBuffer 객체에 의해 참조되므로 JVM 힙의 ByteBuffer 객체가 재활용 되면 관련 오프 힙 메모리가 아래와 같이 해제됩니다.

이미지.png

글쎄요, 오늘의 지식 포인트는 여기에서 공유됩니다. 이 글을 읽으신 후에는 오프 힙 메모리의 개념에 대해 더 명확하게 이해하셨으리라 믿습니다.

코드를 스캔하면 Shishan의 우수한 원본 기사 요약 PDF 600페이지 이상을 무료로 받을 수 있습니다.

이미지

원래 기술 문서 요약

이미지

추천

출처juejin.im/post/7086640445383507981