Decay timer of Jemalloc on android

xiaoxiao2021-02-28  51

A strange ProblemDecay timer of Jemalloc

A strange Problem

android 7.1平台上 Chromium test 出现了一项Fail https://cs.chromium.org/chromium/src/content/browser/tracing/memory_instrumentation_browsertest.cc?l=74&rcl=633bf05fdb96303ebfa68eada1adee9d76dea16f

这项测试检测app初始的内存信息,分配65M的array(保存在 unique_ptr里),然后在JS里使用一些(4M JS array);然后检测app的内存信息。最后,reset这个unique_ptr;再检测一下。预期的结果是内存使用回到初始状态。

为了便于分析问题,我写了个native 测试程序,定义全局变量 nique_ptr buffer_.

std::unique_ptr<char[]> buffer_; void PopulateBuffer() { const int64_t kAllocSize = 65 * 1024 * 1024; buffer_ = std::make_unique<char[]>(kAllocSize); buffer_.reset(); }

测试结果看到native heap占用的内存,不会释放。

Applications Memory Usage (in Kilobytes): Uptime: 179111 Realtime: 179111 Pss Private Private Swap Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ Native Heap 66628 66628 0 0 0 0 0 Dalvik Heap 0 0 0 0 0 0 0 Stack 20 20 0 0 Other dev 0 0 0 0 .so mmap 193 120 12 0 Other mmap 47 20 16 0 Unknown 124 124 0 0 TOTAL 67012 66912 28 0 0 0 0 App Summary Pss(KB) ------ Java Heap: 0 Native Heap: 66628 Code: 132 Stack: 20 Graphics: 0 Private Other: 160 System: 72 TOTAL: 67012 TOTAL SWAP (KB): 0

将buffer_定义成char *类型的全局变量,同样可以看到这种情况。

char* buffer_; void PopulateBuffer() { char* buffer_; const int64_t kAllocSize = 65 * 1024 * 1024; buffer_ = new char[kAllocSize]; delete[] buffer_; buffer_ = nullptr; }

但是将buffer_定义成局部变量,则不会出现这种问题。

void PopulateBuffer() { const int64_t kAllocSize = 65 * 1024 * 1024; char* buffer = new char[kAllocSize]; std::memset(buffer, 1, kAllocSize); delete[] buffer; buffer = nullptr; } or void PopulateBuffer() { const int64_t kAllocSize = 65 * 1024 * 1024; std::unique_ptr<char[]> buffer = std::make_unique<char[]>(kAllocSize); buffer.reset(); }

这个现象只在android 7.1上存在,在其它的版本里没有。android 5.1以后,jemalloc是libc默认的heap 管理器。

这并不是内存泄露,如果再次申请,内存使用量不会增加。过上一段时间后,这个内存还会返还给系统。但是程序已经明确Free了,内存会被hold住一段时间,在低内存设置上会导致内存的紧张。

Decay timer of Jemalloc

为了搞清楚这个问题,大致看了下jemalloc的代码。

Android 7.1 上Decay timer 被下面这个提交设成了1。

https://android.googlesource.com/platform/external/jemalloc/+/08795324eae5f68d211dc5483746af51203dc661^!/

decay timer会影响large object的释放时间,设成1是为了性能问题,因为设成0时,每次free都会purge。decay timer只在android 7.1上被设成了1。

android 8.1上decay timer又被设成了0。

https://android.googlesource.com/platform/external/jemalloc/+/7d7fbe660d1fe68fa412449d6033177319c7da3e^!/

android O上zygote在fork进程时,会通过mallopt将decay timer设成1。所以android O上Java进程在native heap上的表现是和上面问题一样的。native heap上的大块内存会被hold一段时间。

frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

static void PreApplicationInit() { // The child process sets this to indicate it's not the zygote. gMallocLeakZygoteChild = 1; // Set the jemalloc decay time to 1. mallopt(M_DECAY_TIME, 1); }
转载请注明原文地址: https://www.6miu.com/read-2050124.html

最新回复(0)