Typeface.createFromAsset(); 读取Assets中的文件,频繁调用导致的OOM

69 阅读2分钟

1719890915018.jpg

Typeface.createFromAsset(getAssets(), fontFile.getPath()); 读取Assets中的文件,频繁调用大文件会导致oom

assets目录中的文件是只读的以压缩格式存储在 APK 中,并且在运行时需要被解压并加载到某个位置(可能是内存中的缓冲区,也可能是磁盘上的临时文件)中,因此不能直接被映射到内存。

ByteBuffer.allocateDirect(capacity)分配直接内存

由JVM管理的,但它位于Java堆(Heap)之外。因此,它既不属于JVM内部的堆内存,也不完全等同于传统意义上的“VM外部的内存”(系统的物理内存或磁盘空间).

用于提高 I/O 操作的性能,因为它减少了数据在 Java 堆内存和本地内存之间的拷贝次数。

由 -XX:MaxDirectMemorySize 参数控制,默认值通常是堆内存大小,直接内存的每次分配和释放依赖于操作系统的内存管理,而不是 JVM 垃圾回收器.

assetStream.read(buffer.array(), buffer.arrayOffset(), assetStream.available())作用是返回不阻塞地从输入流中读取(或跳过)的估计字节数到内存中。如果文件较大且频繁调用,内存分配压力会更大.

1719890843722.jpg

另一个方法: Typeface.createFromFile(fontFile); 读取本地文件,对比FromAsset方法频繁调用没有出现oom 当使用 FileChannel.map() 方法时,会创建一个到文件内容的内存映射(在虚拟内存空间中),而不是将整个文件内容一次性加载到物理内存中。这意味着操作系统可以按需将文件的各个部分(称为页面)加载到物理内存中,从而节省内存并提高效率。

返回一个MappedByteBuffer 提供了对这块映射内存的直接访问,允许像操作常规字节缓冲区一样来读取和写入数据。但是,由于它是直接映射到文件的,因此对它的修改(在 READ_WRITE 模式下)会直接反映到文件中,而读取操作则直接从映射的内存区域中获取数据,无需通过传统的文件I/O操作。

  1. 性能提升:减少了数据在内存和磁盘之间的复制次数,提高了I/O操作的效率。
  2. 内存效率:由于数据是按需加载的,因此即使处理大文件,也不会立即占用大量物理内存。
  3. 简单性:通过提供对文件的直接内存访问,简化了文件I/O操作的复杂性。

1719890985012.jpg