MIT6.828_HW4_xv6 lazy page allocation

这篇博客探讨了MIT6.828课程作业HW4中的Xv6操作系统如何实现懒页分配,旨在消除sbrk()的内存分配,并在实际使用前延迟物理内存的分配。内容分为两部分,第一部分讲解了如何修改sbrk(),使其仅增加进程大小而不立即分配内存。第二部分介绍了如何实现懒惰分配,避免对未使用页面的预先分配,从而提高效率。

1. HW4_xv6 lazy page allocation

操作系统可以与页表硬件一起使用的许多巧妙技巧之一是堆内存的惰性分配。Xv6应用程序使用sbrk()系统调用向内核请求堆内存。 在我们给你的内核中,sbrk()分配物理内存并将其映射到进程的虚拟地址空间。 有些程序分配到内存但从不使用它,例如实现大稀疏数组。精妙的内核延迟每页内存的分配,直到应用程序尝试使用该页面 - 如页面错误所示。

1.1. Part One: Eliminate allocation from sbrk()

你的新sbrk(n)应该只用n增加进程的大小(myproc() - > sz)并返回旧的大小。

  if(argint(0, &n) < 0)
    return -1;
  addr = myproc()->sz;
  myproc()->sz += n;
  return addr;
$ echo hi
pid 3 sh: trap 14 err 6 on cpu 0 eip 0x112c addr 0x4004--kill proc

"pid 3 sh:trap …"消息来自trap.c中的陷入内核处理程序; 它捕获了页面错误(陷入14或T_PGFLT),xv6内核不知道如何处理。addr 0x4004表示导致页面错误的虚拟地址为0x4004。

1.2. Part Two: Lazy allocation

根据提示来做就比较明了了。主要需要从vm.c中的allocuvm()偷过程。


                
你的查询会返回重复的报表数据(每条报表数据会重复出现,次数等于其关联的标签数量),这是因为 **多表 JOIN 导致的结果集笛卡尔积**。以下是解决方案和优化建议: --- ### **问题分析** 1. **当前查询的问题**: - `LEFT JOIN warehouse_label_manage t4` 会导致每条报表记录根据关联的标签数量重复(例如:1 条报表 + 2 个标签 → 返回 2 条相同报表数据)。 - 如果前端需要 **报表数据 + 关联标签列表**,这种重复数据会导致冗余传输和解析复杂化。 2. **需求目标**: - 返回 **不重复的报表数据**,同时将关联的多个标签合并到一个列表字段中(如 `List<WarehouseLabelManage>`)。 --- ### **解决方案** #### **方案 1:使用 `<resultMap>` + `<collection>`(推荐)** 通过 MyBatis 的嵌套结果映射,将标签列表作为子对象集合映射到报表对象中。 ```xml <!-- 定义结果映射 --> <resultMap id="reportWithLabelsMap" type="com.yunjin.warehouse.report.pojo.vo.WarehouseReportVO"> <!-- 报表基础字段 --> <id column="id" property="id"/> <result column="report_name" property="reportName"/> <result column="source_type" property="sourceType"/> <!-- 其他字段... --> <!-- 关联标签集合 --> <collection property="labelEntity" ofType="com.yunjin.warehouse.report.pojo.entity.WarehouseLabelManage" resultMap="labelResultMap"/> <!-- 引用标签的结果映射 --> </resultMap> <!-- 标签的结果映射(可选) --> <resultMap id="labelResultMap" type="com.yunjin.warehouse.report.pojo.entity.WarehouseLabelManage"> <id column="label_id" property="id"/> <result column="label_code" property="labelCode"/> <result column="label_name" property="labelName"/> <!-- 其他标签字段... --> </resultMap> <!-- 查询语句 --> <select id="selectReportWithLabels" resultMap="reportWithLabelsMap"> SELECT t.id, t.report_name, t.source_type, /* 其他报表字段... */, t4.id AS label_id, t4.label_code, t4.label_name /* 其他标签字段... */ FROM warehouse_report t LEFT JOIN warehouse_report_label_ref t3 ON t3.report_id = t.id AND t3.is_deleted = 0 LEFT JOIN warehouse_label_manage t4 ON t4.id = t3.label_id AND t4.is_deleted = 0 WHERE t.is_deleted = 0 AND t.from_type = 1 AND t.create_dept_id = &#39;A001&#39; </select> ``` **关键点**: - 通过 `resultMap` 的 `<collection>` 将多行标签数据合并到报表对象的 `labelEntity` 列表中。 - 使用 `AS` 为标签字段起别名(避免与报表字段冲突)。 --- #### **方案 2:分两次查询 + 内存组装** 如果数据量较小,可以先查报表列表,再批量查询关联标签,最后在代码中组装。 ```java // 1. 查询报表列表(无标签) List<WarehouseReportVO> reports = mapper.selectReportsByDept("A001"); // 2. 提取报表ID列表 List<Long> reportIds = reports.stream().map(WarehouseReportVO::getId).collect(Collectors.toList()); // 3. 批量查询关联标签 if (!reportIds.isEmpty()) { Map<Long, List<WarehouseLabelManage>> labelsMap = mapper.selectLabelsByReportIds(reportIds); // 4. 组装数据 reports.forEach(report -> report.setLabelEntity(labelsMap.getOrDefault(report.getId(), Collections.emptyList())) ); } ``` ```xml <!-- 批量查询标签 --> <select id="selectLabelsByReportIds" resultType="com.yunjin.warehouse.report.pojo.entity.WarehouseLabelManage"> SELECT lm.* FROM warehouse_label_manage lm JOIN warehouse_report_label_ref ref ON lm.id = ref.label_id WHERE ref.report_id IN <foreach collection="list" item="id" open="(" separator="," close=")"> #{id} </foreach> AND lm.is_deleted = 0 AND ref.is_deleted = 0 </select> ``` **优势**: - 避免复杂 SQL,适合标签数量较多的场景。 - 减少网络传输冗余数据。 --- #### **方案 3:使用 GROUP_CONCAT(MySQL 特有)** 如果数据库是 MySQL,可以通过 `GROUP_CONCAT` 将标签数据合并为字符串,再在代码中解析。 ```xml <select id="selectReportsWithLabels" resultType="com.yunjin.warehouse.report.pojo.vo.WarehouseReportVO"> SELECT t.id, t.report_name, /* 其他报表字段... */, GROUP_CONCAT( CONCAT(t4.id, &#39;:&#39;, t4.label_code, &#39;:&#39;, t4.label_name) SEPARATOR &#39;||&#39; ) AS labelData FROM warehouse_report t LEFT JOIN warehouse_report_label_ref t3 ON t3.report_id = t.id AND t3.is_deleted = 0 LEFT JOIN warehouse_label_manage t4 ON t4.id = t3.label_id AND t4.is_deleted = 0 WHERE t.is_deleted = 0 AND t.from_type = 1 AND t.create_dept_id = &#39;A001&#39; GROUP BY t.id </select> ``` ```java // 解析 labelData 字符串 reports.forEach(report -> { List<WarehouseLabelManage> labels = Arrays.stream(report.getLabelData().split("\\|\\|")) .map(item -> { String[] parts = item.split(":"); WarehouseLabelManage label = new WarehouseLabelManage(); label.setId(Long.parseLong(parts[0])); label.setLabelCode(parts[1]); label.setLabelName(parts[2]); return label; }) .collect(Collectors.toList()); report.setLabelEntity(labels); }); ``` **注意**:此方法依赖数据库特性,且字符串解析可能影响性能。 --- ### **推荐选择** | 方案 | 适用场景 | 优点 | 缺点 | |------|----------|------|------| | **`<resultMap> + <collection>`** | 通用方案 | 纯 SQL 解决,性能最优 | SQL 较复杂 | | **分两次查询** | 标签数量多 | 代码清晰,易维护 | 需要两次数据库访问 | | **GROUP_CONCAT** | MySQL 环境 | 减少查询次数 | 数据库耦合,解析复杂 | **最佳实践**:优先使用 **方案 1**(`<resultMap>`),它是 MyBatis 官方推荐的处理一对多关联的方式。 --- ### **其他优化建议** 1. **分页处理**: 如果报表数据量大,需在 SQL 中添加分页(如 `LIMIT #{offset}, #{pageSize}`)。 2. **延迟加载**: 对标签集合使用 `fetchType="lazy"`,按需加载标签数据: ```xml <collection property="labelEntity" fetchType="lazy" ... /> ``` 3. **索引检查**: 确保 `warehouse_report_label_ref.report_id` 和 `warehouse_label_manage.id` 有索引。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值