2024年最全如何解决写入放大效应导致的内存问题(1),2024年最新鸿蒙app测试面试题

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

这段代码会将整行数据读入内存中进行修改,然后重新写回数据库中,如果数据表非常大,就会导致内存写入放大问题。

解决方式

可以使用 SQLite 的 REPLACE INTO 语句,该语句可以直接更新指定字段,而不需要将整行数据读入内存中:

String sql = "REPLACE INTO user(name, phone) VALUES (?, ?)";
db.execSQL(sql, new String[]{name, newPhone});

使用SharedPreferences进行操作时导致内存写入放大问题
问题

假设有一个存储用户登录信息的SharedPreferences文件,其中包含用户名和密码两个字段。现在需要更新密码,可以使用以下代码实现:

SharedPreferences sp = context.getSharedPreferences("user_login", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("password", newPassword);
editor.apply();

将整个SharedPreferences文件读入内存中,然后修改密码值,最后将整个文件重新写回磁盘中,导致了内存写入放大问题。

解决方式

可以使用FileOutputStream对应的FileChannel进行文件操作,这样可以将修改后的值直接写入文件,而不需要读取整个SharedPreferences文件

File file = new File(context.getFilesDir(), "user_login.xml");
try (FileOutputStream fos = new FileOutputStream(file);
     FileChannel channel = fos.getChannel()) {
    String xml = "<map><string name=\"username\">" + username + "</string><string name=\"password\">" + newPassword + "</string></map>";
    ByteBuffer buffer = ByteBuffer.wrap(xml.getBytes());
    channel.write(buffer);
} catch (IOException e) {
    e.printStackTrace();
}


在使用文件操作时导致内存写入放大问题
问题

假设有一个记录用户日志的文件,每条日志记录占用256字节,现在需要修改其中一条记录的内容,可以使用以下代码实现:

RandomAccessFile raf = new RandomAccessFile("user.log", "rw");
byte[] buffer = new byte[256];
raf.seek(recordOffset);
raf.read(buffer);
// 修改buffer中对应记录的内容
raf.seek(recordOffset);
raf.write(buffer);
raf.close();

这段代码会将整个256字节块读入内存中进行修改,然后重新写回文件中,导致了内存写入放大问题。

解决方式

可以使用内存映射文件的方式来避免内存写入放大问题。例如,可以使用MappedByteBuffer对文件进行操作,该类可以将文件映射到内存中,并且只有在需要写回磁盘时才会进行写操作。以下是修改用户日志记录的示例代码

RandomAccessFile raf = new RandomAccessFile("user.log", "rw");
FileChannel channel = raf.getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, recordOffset, 256);
// 修改map中对应记录的内容
map.force(); // 强制将修改写回磁盘
channel.close();
raf.close();


文件读写时还可能遇到读写次数过多问题,这个我在Bitmap 解码优化中提到过,可以看看,非常有优化价值。

在使用Bitmap进行操作时导致内存写入放大问题
问题

假设有一个需要处理大量图片的应用,现在需要对一张图片进行裁剪操作,可以使用以下代码实现:

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, x, y, width, height);
FileOutputStream fos = new FileOutputStream(outputPath);
croppedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.flush();
fos.close();


这段代码会将整张图片读入内存中进行裁剪操作,然后将裁剪后的图片重新写回磁盘中,导致了内存写入放大问题。

解决方式

使用BitmapRegionDecoder对图片进行裁剪,该类可以只解码出需要的图片区域,并且不会将整张图片读入内存中。以下是使用BitmapRegionDecoder实现裁剪的示例代码:

InputStream is = new FileInputStream(imagePath);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
Bitmap croppedBitmap = decoder.decodeRegion(new Rect(x, y, x + width, y + height), null);
FileOutputStream fos = new FileOutputStream(outputPath);
croppedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.flush();
fos.close();


这段代码会使用BitmapRegionDecoder只解码出需要的图片区域,然后将裁剪后的图片写回磁盘中,避免了内存写入放大问题。

在使用IO流进行操作时导致内存写入放大问题
问题

假设有一个需要将数据写入文件的应用,现在需要写入一个大文件,可以使用以下代码实现:

File inputFile = new File(inputPath);
File outputFile = new File(outputPath);
FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024 * 1024]; // 1MB buffer
int len;
while ((len = fis.read(buffer)) != -1) {
    fos.write(buffer, 0, len);
}
fis.close();
fos.flush();
fos.close();


这段代码会将大文件分成若干个1MB大小的块,然后将每个块读入内存中进行写入操作,导致了内存写入放大问题。

解决方式

可以使用FileChannel进行文件操作,该类可以将文件映射到内存中,并且支持直接对内存进行操作,而不需要将数据读入内存中。以下是使用FileChannel实现文件写入的示例代码:

File inputFile = new File(inputPath);
File outputFile = new File(outputPath);
FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024); // 1MB buffer
while (inChannel.read(buffer) != -1) {
    buffer.flip();
    outChannel.write(buffer);
    buffer.clear();
}
inChannel.close();
outChannel.force(true); // 强制将修改写回磁盘
outChannel.close();
}
}

在使用数据库进行操作时导致内存写入放大问题
问题

假设有一个需要使用SQLite数据库进行操作的应用,现在需要插入大量数据到数据库中,可以使用以下代码实现:

SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
    for (int i = 0; i < count; i++) {
        ContentValues values = new ContentValues();
        values.put("column1", value1);
        values.put("column2", value2);
        values.put("column3", value3);
        db.insert("table", null, values);
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}


这段代码会将大量数据插入到数据库中,导致了内存写入放大问题

解决方式

可以使用SQLiteDatabase的insertWithOnConflict()方法插入多条数据,该方法可以将多条数据插入到数据库中,而不需要将所有数据读入内存中。以下是使用insertWithOnConflict()方法插入多条数据的示例代码:

SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
    for (int i = 0; i < count; i++) {
        ContentValues values = new ContentValues();
        values.put("column1", value1);
        values.put("column2", value2);
        values.put("column3", value3);
        db.insertWithOnConflict("table", null, values, SQLiteDatabase.CONFLICT_REPLACE);
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();


**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

![](https://i-blog.csdnimg.cn/blog_migrate/1e210328c1ebf43f08d3b6c5f5c13b48.png)
![img](https://img-blog.csdnimg.cn/img_convert/fbbd5ea39337426d84d2018e4d93d4c9.png)
![img](https://img-blog.csdnimg.cn/img_convert/6abadb8ed6e44fe27b20967a5b0ea521.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**

..(img-oQ4TWjMT-1715658599986)]
[外链图片转存中...(img-ODC0sZwq-1715658599987)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值