WKWebView(同事遇到的坑mark下)

本文介绍了在iOS应用中使用WKWebView替代UIWebView的过程及优势,包括内存占用减少、JavaScript性能提升、HTML5特性的增强支持等。同时分享了转换过程中遇到的问题及解决方案,如登录状态同步与自定义协议调用的实现。
在iOS8以上使用了WKWebView,WKWebView在内存和性能上都远胜UIWebView

1、在性能、稳定性、功能方面有很大提升(最直观的体现就是加载网页是占用的内存,模拟器加载百度与开源中国网站时,WKWebView占用23M,而UIWebView占用85M);
2、允许JavaScript的Nitro库加载并使用(UIWebView中限制);
支持了更多的HTML5特性;
3、高达60fps的滚动刷新率以及内置手势;
4、将UIWebViewDelegate与UIWebView重构成了14类与3个协议(查看苹果官方文档https://developer.apple.com/library/mac/documentation/Cocoa/Reference/WebKit/ObjC_classic/index.html);


更换后,出现两个大坑:
1、之前通过写NSHTTPCookieStorage与h5同步登录状态失败
2、内部h5使用第三方调起协议全部实效


1、WKWebView不会再从NSHTTPCookieStorage取cookie,而是需要在初始化时通过WKUserScript写入
2、WKWebView无法识别的协议(比如我们第三方调起的)会直接进入失败的delegate方法中,不会像UIWebView那样默认调用openURL方法,所以对于我们自己的的协议头,需要我们手动调用一下openURL
<think>我们正在讨论Java对象头中的Mark Word结构。根据引用[1][3][4],Mark Word是对象头的核心部分,固定占用8字节(64位JVM),用于存储对象的运行时状态。这些状态包括锁状态、哈希码、GC分代年龄、线程ID(偏向锁)和时间戳等。 关键点: 1. Mark Word在不同锁状态下会复用相同的存储空间,因为同一时间对象只能处于一种锁状态。 2. 锁状态由Mark Word的最后2位(或3位,根据具体状态)标识。 接下来,我们将详细解析Mark Word的结构(以64位JVM为例,开启指针压缩的情况): 根据引用[3]和[4],Mark Word的结构如下: 无锁状态(锁标志位01): | 未使用 (25位) | 哈希码 (31位) | 未使用 (1位) | 分代年龄 (4位) | 偏向锁标志 (1位) | 锁标志位 (2位) | | | | | | 0 | 01 | 偏向锁状态(锁标志位01): | 线程ID (54位) | 时间戳 (2位) | 分代年龄 (4位) | 偏向锁标志 (1位) | 锁标志位 (2位) | | | | | 1 | 01 | 轻量级锁状态(锁标志位00): | 指向栈中锁记录的指针 (62位) | 锁标志位 (2位) | | | 00 | 重量级锁状态(锁标志位10): | 指向监视器(Monitor)的指针 (62位) | 锁标志位 (2位) | | | 10 | GC标记(锁标志位11): | 空 (62位) | 锁标志位 (2位) | | | 11 | 注意:以上结构在不同JVM版本和配置(如是否开启偏向锁)中可能略有不同。此外,在32位JVM中,Mark Word为4字节。 现在,我们通过一个具体的例子来展示如何通过JOL工具查看Mark Word: 使用JOL工具(Java Object Layout)可以方便地查看对象头信息,包括Mark Word。 步骤: 1. 添加JOL依赖(Maven): ```xml <dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.17</version> </dependency> ``` 2. 编写代码解析对象头: ```java import org.openjdk.jol.info.ClassLayout; public class MarkWordDemo { public static void main(String[] args) { Object obj = new Object(); System.out.println(ClassLayout.parseInstance(obj).toPrintable()); } } ``` 输出示例(64位JVM,开启指针压缩): java.lang.Object object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) // Mark Word 8 4 (object header: class) 0xf80001e5 // Klass Pointer 12 4 (object alignment gap) // 对齐填充 Instance size: 16 bytes 解析Mark Word(0x0000000000000001): - 最后三位(二进制)是001,表示无锁状态(因为最后两位是01,且倒数第三位是0,表示非偏向锁)。 - 其他位目前没有使用。 如果我们给对象加锁,Mark Word会随着锁状态的变化而变化。 例如,当对象处于轻量级锁状态时,Mark Word的前62位会存储指向线程栈中锁记录的指针,最后两位为00。 引用[2]描述了轻量级锁的获取过程:JVM在当前线程栈帧中创建锁记录(Lock Record)空间,存储锁对象当前的Mark Word拷贝,然后通过CAS操作将Mark Word更新为指向锁记录的指针,并将锁标志位改为00。 总结: - Mark Word是对象头中最重要的部分,它动态地记录了对象在运行时的各种状态。 - 通过分析Mark Word,我们可以了解对象的锁状态、哈希码、GC年龄等信息。 注意:由于Mark Word的结构是JVM内部的实现细节,不同JVM版本和配置可能有所不同,因此实际分析时需结合具体环境。 相关问题: 1. 如何通过对象头判断当前锁状态? 2. 指针压缩对JVM性能有何影响? 3. 为什么Java不提供官方API访问对象头? 4. 如何分析Java对象的内存对齐机制? 5. 对象头在垃圾回收过程中起什么作用? 下面我们将针对用户的问题“Java对象头 Mark Word 结构详解”进行详细回答。</think>### Java对象头Mark Word结构详解 Mark Word是Java对象头的核心组成部分,固定占用**8字节**(64位JVM),用于存储对象在运行时的关键状态信息。其结构会随着对象状态变化而动态调整,以下是详细解析: --- #### 一、Mark Word基础结构(64位JVM) ```plaintext | 锁状态标志 (2bit) | 剩余62bit内容 | |-------------------|----------------------------------------| | 01 | 无锁状态:哈希码+分代年龄等 | | 01 | 偏向锁:线程ID+时间戳+分代年龄 | | 00 | 轻量级锁:指向栈中锁记录的指针 | | 10 | 重量级锁:指向监视器(Monitor)的指针 | | 11 | GC标记:垃圾回收专用标记 ``` > 锁状态标志始终占据**最低2位**,决定剩余62位的含义[^3] --- #### 二、不同状态下的详细结构 ##### 1. 无锁状态(01) ```plaintext | 未使用(25bit) | 哈希码(31bit) | 未使用(1bit) | 分代年龄(4bit) | 偏向锁标志(1bit=0) | 锁标志(01) | ``` - **哈希码**:`System.identityHashCode()`获取的31位值 - **分代年龄**:4bit存储(0-15),记录对象经历GC的次数 - **偏向锁标志**:0表示未启用偏向锁[^3] ##### 2. 偏向锁状态(01) ```plaintext | 线程ID(54bit) | 时间戳(2bit) | 分代年龄(4bit) | 偏向锁标志(1bit=1) | 锁标志(01) | ``` - **线程ID**:持有偏向锁的线程ID - **时间戳**:偏向锁的时间戳(用于撤销机制) - **分代年龄**:同上,但存储空间被复用[^1][^3] ##### 3. 轻量级锁状态(00) ```plaintext | 指向栈中锁记录的指针(62bit) | 锁标志(00) | ``` - 当线程尝试获取锁时,JVM在栈帧中创建**Lock Record** - 通过CAS将Mark Word内容复制到Lock Record - 将Mark Word更新为指向Lock Record的指针[^2] ##### 4. 重量级锁状态(10) ```plaintext | 指向监视器(Monitor)的指针(62bit) | 锁标志(10) | ``` - 当竞争激烈时,升级为重量级锁 - 指向操作系统级别的互斥量(mutex) ##### 5. GC标记状态(11) ```plaintext | 空(62bit) | 锁标志(11) | ``` - 垃圾回收过程中使用的特殊标记 - 表示对象正在被回收或已回收 --- #### 三、关键字段详解 | 字段 | 位数 | 作用 | 状态限制 | |--------------|-------|--------------------------------------------------------------|----------------| | **锁标志** | 2bit | 决定当前锁状态和剩余位含义 | 始终有效 | | **哈希码** | 31bit | 对象标识哈希值(延迟计算) | 仅无锁状态有效 | | **分代年龄** | 4bit | 记录GC次数(到达15次进入老年代) | 无锁/偏向锁有效| | **线程ID** | 54bit | 持有偏向锁的线程ID | 仅偏向锁状态 | | **时间戳** | 2bit | 偏向锁的时效性验证 | 仅偏向锁状态 | | **指针** | 62bit | 指向栈锁记录(轻量锁)或Monitor(重量锁) | 锁状态时有效 | --- #### 四、Mark Word状态转换流程 ```mermaid stateDiagram-v2 [*] --> 无锁: 对象创建 无锁 --> 偏向锁: 单线程访问 偏向锁 --> 轻量级锁: 第二个线程尝试获取 轻量级锁 --> 重量级锁: 自旋失败 重量级锁 --> 无锁: 锁释放 无锁 --> GC标记: 垃圾回收开始 ``` --- #### 五、通过JOL查看Mark Word 使用Java Object Layout工具查看实时状态: ```java import org.openjdk.jol.info.ClassLayout; public class MarkWordDemo { public static void main(String[] args) { Object obj = new Object(); // 无锁状态 System.out.println("==== 无锁状态 ===="); System.out.println(ClassLayout.parseInstance(obj).toPrintable()); synchronized (obj) { // 轻量级锁状态 System.out.println("==== 轻量级锁状态 ===="); System.out.println(ClassLayout.parseInstance(obj).toPrintable()); } } } ``` **输出示例**: ``` ==== 无锁状态 ==== java.lang.Object object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) // 01结尾 8 4 (object header: class) 0xf80001e5 ==== 轻量级锁状态 ==== OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x000070000d7d1d68 (thin lock: 0x000070000d7d1d68) // 00结尾 8 4 (object header: class) 0xf80001e5 ``` --- #### 六、关键注意事项 1. **哈希码延迟计算** 首次调用`hashCode()`时才会生成并存入Mark Word[^3] 2. **偏向锁启用条件** JVM启动4秒后才会激活(防止初始化时竞争) 3. **指针压缩影响** 开启压缩(`-XX:+UseCompressedOops`)时: - Klass Pointer占**4字节** - 对象头总大小:8B(Mark) + 4B(Klass) = 12B → 需4B对齐填充[^1][^4] 4. **32位JVM差异** Mark Word仅**4字节**,存储空间更紧张 5. **锁升级不可逆** 重量级锁无法降级为轻量级锁(但释放后回到无锁) > 💡 **最佳实践**:通过`jol-core`工具分析对象布局,避免直接操作内存[^1][^3] --- ### 总结 Mark Word作为Java对象头的核心组件,通过动态复用62位存储空间,高效管理了对象的运行时状态。理解其结构: 1. 帮助诊断锁竞争问题 2. 优化内存布局 3. 深入理解JVM并发机制 4. 提升垃圾回收效率分析能力 实际开发中推荐使用JOL工具进行安全分析,避免直接操作内存带来的风险[^1][^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值