自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(124)
  • 资源 (1)
  • 收藏
  • 关注

原创 Java类加载机制:Android开发者必须掌握的核心原理

Android类加载机制是开发者必须掌握的核心原理,涉及插件化、热修复、性能优化等关键技术。文章系统介绍了Java类加载的五个阶段(加载、验证、准备、解析、初始化)和内存布局,重点分析了Android特有的类加载体系(BootClassLoader、PathClassLoader、DexClassLoader)。通过实际案例演示了插件化开发、热修复实现和Multidex原理,并提供了性能优化方案和常见问题调试技巧。理解类加载机制能帮助开发者优化应用性能,实现动态加载功能,诊断类冲突问题,是进阶高级开发的必备

2026-04-14 09:15:54 283

原创 理解Android AOT编译与内存映射:从Zygote启动到页表权限隔离

Android系统通过AOT预编译机制实现启动加速,核心在于Zygote进程启动时使用mmap()将预编译的boot.art文件映射到内存。该文件包含Android框架核心类和ART运行时基础代码,以本地机器码形式存储。Zygote通过写时复制技术让所有应用进程共享同一份物理内存页,大幅提升启动速度和内存效率。现代操作系统采用共享内核空间页表设计,结合CPU特权级实现权限隔离,确保内核态不会直接执行用户空间代码。这种内存映射机制是Android性能优化的关键技术之一。

2026-04-10 16:44:15 383

原创 Java类加载机制解析:从JVM启动到双亲委派,再到Android的特殊实现

摘要:本文深入剖析了Java与C++在类加载机制上的本质区别。Java采用运行时动态加载,通过JVM的类加载器体系实现灵活部署;而C++则在编译时静态链接所有类定义。重点解析了Java类加载的五个阶段、双亲委派模型的安全机制,以及Android系统独特的类加载优化(如BootImage)。这种动态加载特性是Java语言灵活性的核心,同时也体现了与C++在"运行时灵活性vs编译时性能"上的设计哲学差异。文章还详细对比了标准JVM与Android运行时在类加载实现上的关键区别。

2026-04-10 16:15:25 446

原创 CMake中解决静态库弱符号覆盖问题的OBJECT库方案

摘要:本文探讨了嵌入式开发中强函数与弱函数在静态库链接时的符号覆盖问题。当强函数和弱函数分别打包成静态库时,不同编译器可能无法正确实现强符号覆盖弱符号。通过分析nm工具显示的符号类型(T表示强符号,W表示弱符号),发现静态库链接过程中强符号可能无法正确覆盖弱符号。提出使用CMake的OBJECT库解决方案,将强符号文件直接编译为对象文件参与链接,确保符号优先级。验证表明该方法能有效实现强符号覆盖,解决了跨编译器兼容性问题,为嵌入式系统开发提供了可靠的接口实现方案。

2026-04-02 15:35:26 148

原创 Linux虚拟文件系统/sys、/dev和 /proc

Linux系统中/proc、/sys和/dev三个虚拟文件系统的核心区别: /proc:提供进程和内核运行时信息(如/proc/cpuinfo),主要用于调试和状态查询; /sys:展示结构化设备树(如/sys/class/),用于查看和配置设备属性; /dev:提供设备操作入口(如/dev/sda),直接进行I/O交互。 三者互补构成用户空间与硬件交互的桥梁:/sys发现设备属性,/dev实际操作,/proc查看系统状态。注意Android中需通过正式API访问,禁止直接操作这些路径。

2026-03-22 09:50:29 380

原创 通过仅暴露C语言头文件和共享库,完美隐藏内部实现细节

本文介绍了在C语言中利用不透明指针模式实现库封装的方法。通过在公开头文件中使用前向声明,仅暴露结构体类型而不展示内部实现,将具体定义隐藏于库内部。该方案通过函数接口访问数据,防止用户直接操作内部成员,有效保护了实现细节。主要优势包括:增强封装性、保持ABI稳定性、实现编译隔离、便于版本维护和知识产权保护。适用于需要隐藏实现、频繁更新或保证兼容性的库开发场景,但不适合性能要求极高或需要栈上分配的情况。

2025-12-28 11:24:22 837

原创 Linux信号量、自旋锁与内存屏障

先看一段Linux信号量down的实现:这个书上也能查到。大意是进程A想要获取信号量,假如没有其他进程已经占有信号量,那么顺理成章地获取sem->count并且减一表示现在资源数减一了。假如已经有其他进程占有信号量,于是sem->count<=0,进入else分支走的函数调用链为:在__down_common内部,当前进程A首先释放自选锁raw_spin_unlock_irq,然后被加入到等待队列后让出cpu进入睡眠。此后其他进程B让出了信号量,执行了sem->count加一,waiter.up

2025-04-27 13:29:58 326

原创 React中的JavaScript语法

最近在看《深入浅出react和redux》。为了更好理解flux于是看了此书的前三张,而React和qml都能采用JS(ECMAScript 6)作为主力语言,在此列举一些个人不甚了解的JS语法以供备忘。

2025-01-28 12:20:56 834

原创 哈希表和双向链表实现LRU

LRU(Least Recently Used)即最近最少使用,是一种内存管理算法。最近在Linux的缓冲区管理也看到了使用LRU算法,即利用哈希表进行 O(1) 复杂度的快速查找,利用双向链表(里面的元素是缓冲头)对缓冲块进行管理和更新。

2024-09-14 15:52:11 629

原创 逻辑地址、线性地址、物理地址和虚拟地址理解

采取的方法是把后面的铁轨即时铺到火车的前面,只要你的操作足够快并能满足需求,列车就能象在一条完整的轨道上运行。逻辑地址和物理地址的“差距”是0xC0000000,是由于虚拟地址->线性地址->物理地址映射正好差这个值。机理 逻辑地址(或称为虚拟地址)到线性地址是由CPU的段机制自动转换的。保护模式未开启分页时,cs作为段选择子,以此获取全局描述符表gdt中段描述符中的段地址,段地址+段内相对偏移地址=物理地址;是指出目前CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。

2024-08-24 20:53:38 497

原创 借助SFINAE判断类成员函数是否存在

分析code可知,Check(0)优先尝试匹配Check(int),而declval()会在不需要知道类型U是否有构造函数的条件下返回U的引用,于是decltype(declval().member(...), true_type)便得以调用类型U的After方法。而我们手动实现的轻量级AOP框架,一般采用动态代理的方式。其实现技术就是拦截目标方法,只要拦截了目标方法,我们就可以在目标方法执行前后做一些非核心逻辑,通过继承方式来实现拦截,需要派生基类并实现基 类接口,这使程序的耦合性增加了。

2024-07-17 17:33:46 494

原创 C++ lambda按引用捕获导致的空悬指针问题

该Wrap也有const版本和非const版本的重载,const版本在捕获类成员函数的指针时,对其用了按值捕获[&, f](即cmd),而非const版本在捕获类成员函数的指针时,对其默认用了按引用捕获[&](即cmd1)。在执行cmd.Execute()是没有问题,而执行cmd1.Execute()发生了crash,通过debug发现按引用捕获类成员函数指针,在Wrap()的时候可以取到类成员函数的地址,但一旦退出Wrap(),该类成员函数的地址不复存在。lambda可以按值捕获,也可以按引用捕获。

2024-07-08 19:01:16 957

原创 分配自定义内存对齐的内存块的aligned_malloc实现分析

于是通过运算reinterpret_cast(reqBlockAddr + offset) & (~alignment),注意这里的alignment已经自减了(如31),结合刚刚所说31的意义,(reqBlockAddr + offset)即(reqBlockAddr + sizeof(void*) + (--alignment))这个地址不但剔除了个额外备用指针,还把31个byte的余量都剔除了,该地址到内存块末尾正好是我们申请的内存100byte。这样对常规的数据来说没有问题。

2024-06-24 11:54:17 847

原创 《深入C++11 代码优化与工程应用》勘误表(二)

1. 书中做了个包装函数,p是第三方库返回的裸指针。此包装函数为了用智能指针包裹以起到自动释放堆内存的目的。既然已经return一个临时变量没有必要在声明sp变量名,编译会报错。额外要注意,void*类型的指针初始化指针指针需要指定删除器,貌似默认的不支持。

2024-05-29 15:14:05 304

原创 QML的ListView在动态删除Item时无法更新spacing

一旦model的数据被准备好,比如model有8项那么ListView就会加载8个delegate,与之对应的spacing就会有7个。如果这时在qml侧做手脚,进行一定的过滤如删除4个delegate,妄图满足某些条件就返回一个无效的delegate,达到只加载4个delegate的效果。这也许是Qt不够智能的原生问题,不管我在现在code里面是让loader返回undefined还是null,抑或是让delegate如text的高度为0,visible为false都无法解决上述问题。

2024-05-21 17:11:58 465

原创 《深入C++11 代码优化与工程应用》勘误表(一)

这本书其实谬误还不少,我网上找了的确提到了一些勘误但还是有些漏网之鱼。C++11从标准发布以来都过去10年以上了,看此书目的无外乎是11是后续版本的基础,并且我工作鲜少真正手写C++,巩固一下还是很有必要的。况且《深入C++11》提到了很多模板元编程的例子,现代C++其实要掌握好感觉对模板提出的更高的要求。

2024-05-19 22:32:59 372

原创 C++可变参数模板类通过递归和特化方式展开

可以看到普通版本压根没有起作用,原书中普通模板的写法其实误导了我,以为Contains匹配特化版而Contains匹配普通版,其实不是的。除了第一行的template外,只要类名后面还带有有尖括号的叫做模板特化,也就是说这段code第一个模板是Contains普通模板,后面两个是Contains特化模板。于是乎,当语句Contains::value想要实例化时尽量先找特化版本,无特化可选才匹配普通版本,下面是借助。

2024-05-09 17:22:39 593

原创 C++可变参数模板中的省略号

看可变参数模板代码时常会遇到省略号的使用,这类奇特的“...”出现位置还不固定,容易引起困惑。C++最近一直不用都快废了,在此想对省略号的使用做个简单归纳以提醒自己。可变参数模板以两种方式使用省略号。在参数名称的左侧,表示“参数包”,在参数名称的右侧,意为将参数包逐项展开。

2024-05-01 19:52:17 871

原创 在Visual Studio Code macOS上尽量用Clang编译C++

很可能因为launch.json的预制配置并没有"g++ build and debug active file", 直接run的话大概率会无法编译.然后在当前c++ file点击右上角的Debug C/C++ File就可以Run了.

2024-04-22 15:15:02 1175

原创 逻辑代数运算律

这里谈及的是二元逻辑运算符&&(与)、||(或)以及一元运算符!(非). 这些运算符的运算律还是挺重要的, 因为先入为主写就的代码会按照原来的逻辑思维定势写出比较复杂的&&、||、!的混合条件case, 而通过运算律可以简化他们, 特别是在重构代码的时候会派上用场.

2024-04-10 11:29:38 412

原创 不要乱用Qml属性implicitWidth与implicitHeight

implicitWidth/Height一般用在可重用控件,它也不是必要的,QtQuick可以没有者两个属性,只因为了方便而存在。它提供了项目的自然大小的提示,但没有强制执行此大小。如果没有设置width/height系统就会默认使用implicitWidth/Height。这里要注意,如果设置的implicitWidth/Height大于设置的width/height,那么会优先启用implicitWidth/Height。width/height控件属性则为控件的宽度和高度。

2024-03-20 12:20:34 378

原创 记一次无法ping通switch处理

网络小白,仅仅在工作中需要telnet到switch。奈何之前不知什么原因一直无法ping通该switch,很久只能使用串口连接来配置了。而今遇到了使用脚本telnet switch的场景,不得不再次面对这个问题。结果发现并没有我的switch ip所属的Vlan 802。让管理员添加Vlan 802后,问题得到解决。

2024-01-31 17:19:35 446

原创 《Linux0.11源码解读》理解(五) head之开启分页

我们从最后一个页表的最后一项始按倒退填写。一个页表的最后一项在页表中的偏移地址是1023*4 = 4092(表项从0到1023,偏移地址=序号*4)。于是4(页表数)* 1024(页表项数) * 4KB(一页大小)= 16MB,即1个页目录表 + 4个页表就能指示全部的16M内存。在保护模式下,ds段选择子,如0x10指向的是全局描述符表中的第二个段描述符(数据段描述符),里面内容中的段基址是 0。,共有4个页表只需设置4项(页目录和每个页表项本身也占据4K,每项4byte,一共可以设置1k个项/条目)。

2023-07-18 22:45:49 699 1

原创 QML MouseArea堆叠时传递组合事件

我们知道mouseX和mouseY是在此MouseArea内部的相对坐标,一个mouseArea使用固然没有问题,但是我发现一旦above传递给beneath后,above接收到的mouseX/Y正确无误但是beneath的mouseX/Y是不对的(假如我们对坐标感兴趣的话)!2方MouseArea各自接受自己的,互不影响。一旦above在onPressed设置mouse.accepted = false,beneath固然能收到pressed和released,但是above只能收到pressed了。

2023-07-13 18:54:24 486

原创 《Linux0.11源码解读》理解(四) head之重新设置IDT/GDT

上节提到,现在cs:ip指向0地址,此处存储着作为操作系统核心代码的system模块,是由head.s和 main.c以及后面所有源代码文件编译链接而成。head.s(以下简称head)紧挨着main.c,我们先执行head。

2023-05-27 22:51:02 1334

原创 《Linux0.11源码解读》理解(三) 执行setup

上一节的最后jmpi把cs:ip设置为0x9020:0000。于是CPU开始,它的作用是。

2023-05-17 22:25:01 563

原创 《Linux0.11源码解读》理解(二) 加载setup、加载system

现在CPU开始执行bootsect,它的作用是把第二部分、第三部分程序陆续加载到内存中。而把放到合理的内存位置需要先对内存进行规划。根据上一节,boostsect当前所在内存位置是0x07c0,大小为512byte,现在要将其挪动到内存的。除此以外,还要将位于硬盘上的4个(SETUPLEN)扇区的setup程序加载到内存的;最后要将system程序(内核)加载到内存的,并指定了其末尾位置(ENDSEG)。

2023-05-04 22:05:45 970 4

原创 《Linux0.11源码解读》理解(一) 从开机到加载bootsec

计算机启动时, 内存(RAM)没有任何东西, 自然也无法跑操作系统. 但是可以执行固化在ROM里面的BIOS程序. 在按下电源键的一刻. CPU的cs和ip寄存器硬件被设置为0xf000和0xfff0, 于是cs:ip也就指向0xffff0这个地址, 而这个地址正是指向了ROM的BIOS范围(这里是0xfe000~0xfffff, 20根地址线全部范围0x0000~0xfffff, 这个范围包括RAM、ROM、其他map的外设).下的程序,它的中断调用都是建立在中断向量表基础上的。

2023-04-20 16:09:00 630

原创 QML Text属性width、implicitWidth、contentWidth更新时序

对于动态内容Text, width被getHgWidth绑定, 故function一定先调用, 不论implicitWidth和contentWidth是否为0. 一旦有text动态更新,先变化的属性是implicitWidth, 这将trigger function再次调用,这将导致width更新, 而最后更新的是contentWidth.说句题外话,我之前getHgWidth想用Text A和Text B的visible属性来作为function参数来更新witdh,但发现虽然每次。

2023-03-16 15:52:21 1108

原创 《STL源码剖析》理解之将类成员函数和for_each等算法结合

既然抱怨的是“_Func这个函数不能转为接受一个参数的函数”,但以上代码使用的函数“print2”明明是只接受一个参数的函数,那为什么编译器还会报这个错呢?显然print2的参数是int而不是Int。mem_fun_ref返回一个仿函数,而这个仿函数接受两个参数,一个是T*指针(也就是方法所在类对象的指针,可理解为this),第二个才是我们需要的Int。类成员函数可以通过函数适配器(function adapters)包装成一个仿函数(重载了operator()的类),将其搭配于STL算法一起使用。

2023-02-24 23:48:34 526

转载 修改Eclipse字体以及背景颜色

3. 选中 Test Editors,右边出现Test Editors面板。3. 在右边的对话框里选择Java - Java Editor Text Font,点击出现的修改(Change)按钮,可以设置显示在在主窗体中程序的字体大小。2. 展开Appearence标签,选中Colors And Fonts选项,展开。1. 打开window->Preference,弹出Preference面板。2. 展开General标签,选中Editors选项,展开。4. 护眼色数值(16进制): #C7EDCC。

2022-12-19 14:02:51 1275

转载 将文件中的tab转换为space空格

在Linux中还有其它的方法可以将文件中的tab和space相互转换。来键入的,此方法将所有tab替换为4个空格。使用expand和unexpand命令。,同样将所有tab替换为4个空格。在vi中使用替换命令。

2022-11-17 16:07:43 1256

原创 Cisco switch常用命令

monitor session destination interface //接分析工具的端口(PC抓包)如phone连到Gi1/0/2,pc连到 Gi1/0/1,则用wireshark抓电脑网卡的包抓到的就是phone的包。monitor session source interface //定义被监控的端口。switchport access vlan //port一对一设置vlan。

2022-11-07 12:27:54 1146

转载 Git远程分支操作

使用git fetch不会合并远程分支,需要再显式使用git merge命令。如果远程分支已在本地分支之后,可以不删除远程分支而使用强制方式推送到远程分支。获取远程分支数据, 远程仓库名就是add remote -add的名字。设置要推送的远程分支为本地待跟踪,方便后续拉取代码操作。如果远程分支名和本地分支名一致,那么使用简易方式。如果需要本地分支和远程分支名一致,实现如下。设置本地分支想要跟踪的远程分支。修改要跟踪的远程分支,使用参数。显示本地分支和远程分支的关系。推送本地分支内容到远程分支。......

2022-08-08 18:04:30 1346

转载 Git本地分支操作

注意, 这里说的分支都是指本地而非远程的.

2022-08-08 17:27:27 391

原创 嵌入式Linux为Qt定制keymap

而嵌入式平台按键有限且要自行指定keycode,这时不再使用上述keymapDefault的缺省实现.比如将输入设备gpiokeys实现为驱动/dev/input/event1(假如他的F8keycode是82,非66),那么如何让Qt使用/dev/input/event1并使用新的keycode--Key_F8映射关系呢?...

2022-07-25 22:46:28 956 1

原创 从 typedef struct T *T 看C语言的命名空间

最近在看《C语言接口与实现》一书. 第二章提到, 一个ADT(抽象数据类型)就是一个借口, 其标准范例是栈. 其接口定义如下所示:众所周知宏定义的作用仅仅是一个替换而已, 因此typedef这句话实际为:按照书上说法, Stack_T对外接口表现为一个“不透明指针”. 我起初理解是, 以后凡是看到Stack_T的地方实际指代的都是指针Stack_T*. 乍看起来这种理解没错, 但看一下栈的实现后, 便发生了理解不能的事情:这里#define 指令又把T定义为Stack_T的缩写. 问题来了

2022-07-02 17:30:35 708

转载 cpu的位宽、操作系统的位宽和寻址能力的关系

cpu的位宽暂时没有严格的定义,但是一般从数值上来讲:cpu的位宽 = 数据总线的位宽 = cpu内部通用寄存器的位宽 = 机器字长放出一个百度百科对于机器字长的定义供大家理解概念:CPU的寻址能力与它的地址总线位宽有关,与数据总线宽度(CPU位宽=数据总线位宽)无关。16位CPU的地址总线位宽可以是20位,32位CPU的地址总线可以是36位,64位CPU的地址总线位宽可以是40位。NOTE:CPU内部寄存器之间、CPU和外设的数据交互是通过总线来实现的,下图展示了cpu和外部设备(存储器和IO)之间的总线

2022-06-30 16:44:04 4504 1

原创 Git fork, branch的异同及其cherry-pick和pull request操作

对于原生的Git来说,是没有fork的,fork是类似GitHub、码云等等在线代码托管平台提出来的功能. fork可以克隆出一个仓库的新拷贝,包含原仓库(即upstream repository,上游仓库)所有内容,如分支、Tag、提交. 若在被克隆项目进行修改和提交, 则完全不影响原仓库. 而若要将修改推到原仓库, 需要pull request,一旦对方接受,修改便合并入原仓库. branch是一个Git操作,可以开启另一个分支, 在原先仓库上得到一个新的分支. 处理分支的方式十分轻量,创建新分支速

2022-06-26 11:07:03 2594

原创 Docker设置DNS, 或直接配置静态域名

需要在docker内通过内网域名下载文件. 也许在家办公, 访问DNS服务器的不稳定的原因, 默认的 8.8.8.8 或 8.8.4.4 (Google免费的) 无法解析诸如公司的内部域名 sqbu-github.xxxxx.com. 而在宿主机上可以进行操作:于是乎, 在宿主机通过ping域名, 或者利用nslookup可以获得域名的IP, 以及宿主机所使用的DNS服务器:那么如果让docker内识别出域名sqbu-github.xxxxx.com呢? 经查阅有若干种方式:加入刚.

2022-06-22 00:21:21 2121

opengl es win32模拟器(63位也适用)

opengl es win32模拟器(63位也适用) 亲测可用~~~

2018-06-03

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除