Cached JSP引发的问题与思考

在项目中,修改Constants接口里常量值,JSP未更新显示,引发混淆。推测是Cached JSP所致,因为JSP本质是Servlet,首次访问会翻译编译成.class文件,之后访问不再编译。为探究JSP依赖的class变化是否引发重新编译,作者做了简单试验。

       在最近的Project中遇到了一个表面上看起来蛮奇怪的问题。具体问题是这样的,在Project中,所有跨模块的constant都会定义在一个名字叫Constants的interface中,然后在JSP里面,我们也会相应地使用到这些constant。 每当更改了Interface里面某一个constant的值的时候,在JSP中并不会反应出来,从而引起了很多混淆。由于Constants是由我来负责的,每当我修改了constant的值,都会有同事问我,到底constant的值修改了没有,为什么JSP上面没有看到更新的值。一开始我也很迷惑,后来仔细一想,应该是由于Cached JSP引起的。大家都知道,JSP的本质仍然是Servlet,一个更新的JSP文件在第一次被访问的时候,会translate(翻译)成一个Servlet,然后再被编译成.class文件,存放在固定的一个folder中,以后的访问就不必再进行编译的动作,从而提高JSP的访问速度。而JSP的编译动作通常都会在JSP本身发生改变后进行,那么JSP所依赖的class发生变化之后,是不是也会引发JSP的重新编译呢?带着这个问题,我做了一个很简单的试验。
        我在WSAD中建立了一个很简单的Dynamic Web Project,这个Project中之包含了一个JSP:Test.jsp和一个interface:Constants。具体代码如下:

None.gif<HTML>
None.gif
<HEAD>
ExpandedBlockStart.gifContractedBlock.gif
<%dot.gif@ page import="constants.Constants" %>
None.gif
<TITLE>Test.jsp</TITLE>
None.gif
</HEAD>
None.gif
<BODY>
None.gif
<P><%=Constants.NAME%></P>
None.gif
</BODY>
None.gif
</HTML>
None.gif
                                                                          ( Test.jsp )

ExpandedBlockStart.gifContractedBlock.gifpublic interface Constants dot.gif{
InBlock.gif    
public static final String NAME = "Java";
ExpandedBlockEnd.gif}
                                                                      ( Constants.java )

编译Project并且在浏览器中访问Test.jsp,我们可以看到"Java"字样出现在屏幕上。接着,我将NAME的值从"Java"改为"Perhaps"并将Project编译。但是不管我是以刷新页面的方式还是重启Server,都没有办法看到我期待的"Perhaps"。当然,改动一下Test.jsp就可以得到我想要的结果。从这个小小的试验可以看出,Constants这个interface的改变并没有让JSP重新编译。 试验到这里并没有结束,因为同事告诉我说,interface的改变没有引发依赖这个interface的JSP文件的编译动作,是因为interface中variable是final所致。既然有了这样的解释,我就再来验证一下。
        我新建了一个class:NewConstants并且在Test.jsp中增加了对它的访问。具体代码如下:

ExpandedBlockStart.gifContractedBlock.gifpublic class NewConstants dot.gif{
InBlock.gif    
public static final String NAME = "Fantasy";
ExpandedBlockEnd.gif}

重复以上的步骤,当我改变了NAME的值之后,譬如改为"Soft",编译Project却会引发JSP的重新编译。 由此可以得出,final关键字的使用并非问题的关键所在。
        最后我得出的结论就是JSP是否能够自动编译,需要看所依赖的是class还是interface。如果是class,则class的改动也会相应引起JSP的编译,而interface则不会。这只是我的试验的结论,哪位朋友可以更深入地对这个问题解释一下呢?在下不胜感激了。:)
内容概要:本文围绕EKF SLAM(扩展卡尔曼滤波同步定位地图构建)的性能展开多项对比实验研究,重点分析在稀疏稠密landmark环境下、预测更新步骤同时进行非同时进行的情况下的系统性能差异,并进一步探讨EKF SLAM在有色噪声干扰下的鲁棒性表现。实验考虑了不确定性因素的影响,旨在评估不同条件下算法的定位精度地图构建质量,为实际应用中EKF SLAM的优化提供依据。文档还提及多智能体系统在遭受DoS攻击下的弹性控制研究,但核心内容聚焦于SLAM算法的性能测试分析。; 适合人群:具备一定机器人学、状态估计或自动驾驶基础知识的科研人员及工程技术人员,尤其是从事SLAM算法研究或应用开发的硕士、博士研究生和相关领域研发人员。; 使用场景及目标:①用于比较EKF SLAM在不同landmark密度下的性能表现;②分析预测更新机制同步否对滤波器稳定性精度的影响;③评估系统在有色噪声等非理想观测条件下的适应能力,提升实际部署中的可靠性。; 阅读建议:建议结合MATLAB仿真代码进行实验复现,重点关注状态协方差传播、观测更新频率噪声模型设置等关键环节,深入理解EKF SLAM在复杂环境下的行为特性。稀疏 landmark 稠密 landmark 下 EKF SLAM 性能对比实验,预测更新同时进行非同时进行对比 EKF SLAM 性能对比实验,EKF SLAM 在有色噪声下性能实验
内容概要:本文围绕“基于主从博弈的售电商多元零售套餐设计多级市场购电策略”展开,结合Matlab代码实现,提出了一种适用于电力市场化环境下的售电商优化决策模型。该模型采用主从博弈(Stackelberg Game)理论构建售电商用户之间的互动关系,售电商作为领导者制定电价套餐策略,用户作为跟随者响应电价并调整用电行为。同时,模型综合考虑售电商在多级电力市场(如日前市场、实时市场)中的【顶级EI复现】基于主从博弈的售电商多元零售套餐设计多级市场购电策略(Matlab代码实现)购电组合优化,兼顾成本最小化收益最大化,并引入不确定性因素(如负荷波动、可再生能源出力变化)进行鲁棒或随机优化处理。文中提供了完整的Matlab仿真代码,涵盖博弈建模、优化求解(可能结合YALMIP+CPLEX/Gurobi等工具)、结果可视化等环节,具有较强的可复现性和工程应用价值。; 适合人群:具备一定电力系统基础知识、博弈论初步认知和Matlab编程能力的研究生、科研人员及电力市场从业人员,尤其适合从事电力市场运营、需求响应、售电策略研究的相关人员。; 使用场景及目标:① 掌握主从博弈在电力市场中的建模方法;② 学习售电商如何设计差异化零售套餐以引导用户用电行为;③ 实现多级市场购电成本风险的协同优化;④ 借助Matlab代码快速复现顶级EI期刊论文成果,支撑科研项目或实际系统开发。; 阅读建议:建议读者结合提供的网盘资源下载完整代码案例数据,按照文档目录顺序逐步学习,重点关注博弈模型的数学表达Matlab实现逻辑,同时尝试对目标函数或约束条件进行扩展改进,以深化理解并提升科研创新能力。
**`cached` 进程和 `empty` 进程是 Android 内存管理中的两类特殊进程,前者代表可回收的缓存数据占用,后者是系统预留的轻量级空进程,二者共同参内存压力下的资源释放策略**。以下是详细的技术分析: --- ### **1. `cached` 进程:可回收的缓存数据容器** #### **1.1 定义作用** - **`cached` 进程**: 指 Android 系统中被标记为 `oom_adj`(Android 8.0 前)或 `oom_score_adj`(Android 8.0 后)值较低(如 `0`~`100`)的进程,其内存占用主要为**可回收的缓存数据**(如应用缓存、图片资源等)。 - **核心特性**: - **内存可回收**:当系统内存不足时,`lowmemorykiller` 会优先终止此类进程,释放其占用的物理内存。 - **快速重启**:终止后,若用户再次访问相关应用,系统可快速重建进程并恢复缓存。 - **低优先级**:在内存压力下,其存活优先级低于前台应用和可见应用。 #### **1.2 技术实现** - **标记机制**: Android 通过 `ActivityManagerService` 动态调整进程的 `oom_score_adj`,`cached` 进程通常满足: ```java // 伪代码:判断进程是否为 cached 类型 boolean isCachedProcess(ProcessRecord proc) { return proc.oomScoreAdj >= 0 && proc.oomScoreAdj <= 100; } ``` - **内存管理**: - **共享内存**:多个 `cached` 进程可能共享同一份缓存数据(如通过 `Ashmem` 匿名共享内存)。 - **LRU 策略**:系统按最近最少使用(LRU)顺序终止 `cached` 进程。 #### **1.3 实际场景** - **案例 1**:用户关闭一个后台应用(如浏览器),其进程被标记为 `cached`,内存被保留为缓存。 - **案例 2**:当系统内存不足时,`lowmemorykiller` 终止最久未使用的 `cached` 进程,释放内存供前台应用使用。 --- ### **2. `empty` 进程:系统预留的轻量级空进程** #### **2.1 定义作用** - **`empty` 进程**: 指 Android 系统中**无任何活动组件**(如 Activity、Service)的空进程,其唯一目的是**保留应用进程结构**,加速后续启动。 - **核心特性**: - **极低内存占用**:仅保留进程的基本结构(如 PID、VM 堆栈),不占用应用数据内存。 - **快速复用**:当用户重新打开应用时,系统可复用 `empty` 进程的 VM 上下文,避免冷启动开销。 - **临时存活**:在内存压力下,`empty` 进程会被优先终止(优先级低于 `cached` 进程)。 #### **2.2 技术实现** - **创建条件**: 当应用进程的所有组件(Activity、Service 等)被销毁后,系统可能保留其进程为 `empty` 状态,条件包括: - 应用配置了 `android:persistent="true"`(系统应用)。 - 系统预测用户可能快速重新打开该应用(如最近使用的应用)。 - **终止条件**: - 内存不足时,`lowmemorykiller` 按 `oom_score_adj` 顺序终止 `empty` 进程(通常 `oom_score_adj` 高于 `cached` 进程)。 - 系统主动清理长时间未使用的 `empty` 进程(通过 `ProcessList` 的 `emptyProcessLimit` 参数控制)。 #### **2.3 实际场景** - **案例 1**:用户退出微信主界面(无前台 Activity),微信进程变为 `empty` 状态,保留进程结构。 - **案例 2**:当用户再次点击微信图标时,系统复用 `empty` 进程快速恢复界面,避免冷启动延迟。 --- ### **3. 二者 `lowmemorykiller` 的协作** #### **3.1 内存压力下的终止顺序** Android 的 `lowmemorykiller` 根据 `oom_score_adj` 决定进程终止顺序,典型优先级如下(从低到高): 1. **`empty` 进程**:`oom_score_adj` 通常为 `500`~`600`。 2. **`cached` 进程**:`oom_score_adj` 通常为 `0`~`100`。 3. **后台服务进程**:`oom_score_adj` 通常为 `100`~`500`。 4. **前台应用进程**:`oom_score_adj` 通常为 `-1000`~`0`(几乎不被终止)。 #### **3.2 终止逻辑示例** ```java // 伪代码:lowmemorykiller 的终止逻辑 void killProcessesIfNeeded(int minFreeMemory) { List<ProcessRecord> processes = getProcessesSortedByOomScoreAdj(); for (ProcessRecord proc : processes) { if (getCurrentFreeMemory() < minFreeMemory) { if (proc.isEmpty() || proc.isCached()) { killProcess(proc); // 优先终止 empty 或 cached 进程 } } else { break; } } } ``` --- ### **4. 关键配置参数** #### **4.1 `cached` 进程相关参数** ```bash # 查看 cached 进程的 oom_score_adj 范围(Android 8.0+) cat /proc/[pid]/oom_score_adj # 典型值:0~100 # 系统配置:调整 cached 进程的内存权重 adb shell settings put global lowmemorykiller_adj 0,100,200,300,400,500 ``` #### **4.2 `empty` 进程相关参数** ```bash # 查看 empty 进程的 oom_score_adj(通常为 500~600) cat /proc/[pid]/oom_score_adj # 系统配置:限制 empty 进程的最大数量 cat /sys/module/lowmemorykiller/parameters/empty_process_limit # 输出示例: # 10 # 最多允许 10 个 empty 进程 ``` --- ### **5. 厂商定制优化** #### **5.1 华为 HybridSwap 的影响** - **动态调整优先级**: 华为通过 HybridSwap 分层交换机制,在内存压力下动态调整 `cached` 进程的 `oom_score_adj`,延迟其终止时间。 - **`empty` 进程复用优化**: 将 `empty` 进程 `zram` 压缩内存结合,减少复用时的物理内存占用。 #### **5.2 小米内存扩展** - **`cached` 进程压缩**: 将 `cached` 进程的内存页优先交换到 `zram`,而非直接终止。 - **`empty` 进程预加载**: 在充电时预创建常用应用的 `empty` 进程,提升后续启动速度。 --- ### **6. 调试监控** #### **6.1 查看进程类型** ```bash # 通过 adb 列出所有进程及其 oom_score_adj adb shell ps -A | grep -E "cached|empty" # 输出示例: # u0_a123 1234 0.0 0.1 123456 7890 ? S Jan01 0:00 com.example.app:cached # u0_a456 5678 0.0 0.0 23456 1234 ? S Jan01 0:00 com.example.app:empty ``` #### **6.2 触发内存压力测试** ```bash # 模拟内存不足(需 root) adb shell echo 1 > /proc/sys/vm/drop_caches adb shell stress --vm-bytes 2G --vm-keep -m 1 # 分配 2GB 内存 ``` --- ### **7. 总结** | **特性** | **`cached` 进程** | **`empty` 进程** | |------------------|---------------------------------------------|---------------------------------------------| | **定义** | 包含可回收缓存数据的进程 | 无活动组件的空进程 | | **内存占用** | 较高(含缓存数据) | 极低(仅进程结构) | | **终止优先级** | 低(`oom_score_adj` 0~100) | 较高(`oom_score_adj` 500~600) | | **复用机制** | 终止后需重新加载数据 | 复用 VM 上下文,快速恢复 | | **典型场景** | 后台应用缓存 | 应用退出后的快速重启 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值