Skip to content

Commit a782cd7

Browse files
committed
add notes
1 parent 7e95793 commit a782cd7

11 files changed

Lines changed: 562 additions & 19 deletions

JavaKnowledge/JVM垃圾回收机制.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
# JVM垃圾回收机制
22

3+
4+
当前主流的商用程序语言(Java、C#)的内存管理子系统都是通过可达性分析(Reachability Analysis)算法来判定对象是否存活的。
5+
6+
这个算法的基本思路就是通过一系列被称为"GC Roots"的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所做过的路径称为"引用链"(Reference Chain),
7+
如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。
8+
9+
10+
如下图: 对象object5、object6、object7虽然互有关联,但是它们到GC Roots是不可达的,因此它们将会被判定为可回收的对象。
11+
12+
13+
![image](https://raw.githubusercontent.com/CharonChui/Pictures/master/reachability_analysis.png)
14+
15+
16+
在Java技术体系里面,固定可作为GC Roots的对象包括以下几种:
17+
18+
- 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
19+
20+
- 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
21+
22+
- 在方法区中常量引用的对象,譬如字符串常量池(String Table)中的引用。
23+
24+
- 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
25+
26+
- Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointException、OutOfMemoryError)等,还有系统类加载器。
27+
28+
- 所有被同步锁(synchronized关键字)持有的对象。
29+
30+
- 反应Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
31+
32+
33+
除了这些固定的GC Roots集合以外,根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象“临时性”地加入,共同构成完整GC Roots集合。譬如后文将会提到的分代收集和局部回收(Partial GC),如果只针对Java堆中某一块区域发起垃圾收集时(如最典型的只针对新生代的垃圾收集)​,必须考虑到内存区域是虚拟机自己的实现细节(在用户视角里任何内存区域都是不可见的)​,更不是孤立封闭的,所以某个区域里的对象完全有可能被位于堆中其他区域的对象所引用,这时候就需要将这些关联区域的对象也一并加入GC Roots集合中去,才能保证可达性分析的正确性。
34+
35+
36+
37+
38+
339
[Java内存模型](https://github.com/CharonChui/AndroidNote/blob/master/JavaKnowledge/Java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B.md)如下图所示,**堆和方法区是所有线程共有的**,而虚拟机栈,本地方法栈和程序计数器则是线程私有的。
440

541
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/jvm.png)
@@ -460,4 +496,4 @@ NUMA 是一种多核服务器的架构,简单来讲,一个多核服务器(
460496
---
461497

462498
- 邮箱 :charon.chui@gmail.com
463-
- Good Luck!
499+
- Good Luck!

JavaKnowledge/volatile和Synchronized区别.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ ctorInstance(memory); //2.初始化对象
183183

184184
指令重排序后,在多线程情况下,可能会发生A线程正在new对象,执行了3,但还没有执行2。此时B线程进入方法获取单例对象,执行同步代码块外的非空判断,发现变量非空,但此时对象还未初始化,B线程获取到的是一个未被初始化的对象。使用volatile修饰后,禁止指令重排序。即,先初始化对象后,再设置instance指向刚分配的内存地址。这样就就不存在获取到未被初始化的对象。
185185

186+
187+
188+
那为何说它禁止指令重排序呢?从硬件架构上讲,指令重排序是指处理器采用了允许将多条指令不按程序规定的顺序分开发送给各个相应的电路单元进行处理。但并不是说指令任意重排,处理器必须能正确处理指令依赖情况保障程序能得出正确的执行结果。譬如指令1把地址A中的值加10,指令2把地址A中的值乘以2,指令3把地址B中的值减去3,这时指令1和指令2是有依赖的,它们之间的顺序不能重排——(A+10)*2与A*2+10显然不相等,但指令3可以重排到指令1、2之前或者中间,只要保证处理器执行后面依赖到A、B值的操作时能获取正确的A和B值即可。所以在同一个处理器中,重排序过的代码看起来依然是有序的。因此,lock addl$0x0,(%esp)指令把修改同步到内存时,意味着所有之前的操作都已经执行完成,这样便形成了“指令重排序无法越过内存屏障”的效果。
189+
190+
191+
186192
## synchronized
187193

188194
**synchronized实现同步的基础是:Java中的每个对象都可作为锁。所以synchronized锁的都对象,只不过不同形式下锁的对象不一样。**

JavaKnowledge/强引用、软引用、弱引用、虚引用.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@
6666
6767
![](https://raw.githubusercontent.com/CharonChui/Pictures/master/reference_compare.jpg)
6868
69+
70+
无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象是否引用链可达,判定对象是否存活都和“引用”离不开关系。在JDK 1.2版之前,Java里面的引用是很传统的定义:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称该reference数据是代表某块内存、某个对象的引用。
71+
72+
73+
在JDK 1.2版之后,Java对引用的概念进行了扩充,将引用分为强引用(Strongly Re-ference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。
74+
75+
76+
- 强引用是最传统的“引用”的定义,是指在程序代码之中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。
77+
78+
- 软引用是用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2版之后提供了SoftReference类来实现软引用。
79+
80+
- 弱引用也是用来描述那些非必须对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2版之后提供了WeakReference类来实现弱引用。
81+
82+
- 虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2版之后提供了PhantomReference类来实现虚引用。
83+
6984
---
7085
7186
- 邮箱 :charon.chui@gmail.com

VideoDevelopment/OpenGL/1.OpenGL简介.md

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ OpenGL ES由OpenGL裁剪而来,因此有必要了解一下两者版本的对
4343

4444

4545

46+
图像数据无非是一个个的像素点,对图像数据的处理无非是对每个像素点进行计算后重新赋值,一般来说对每个像素点的计算都比较独立,计算也相对简单。CPU虽然计算能力强大,但是并行处理能力有限,对一张720P的图片,一共包含720*1280=921600个像素,要进行这么多次运算,CPU也要望洋兴叹了。GPU与CPU相比最大的优势就是并行处理能力,一般移动端的GPU也要包含数千个处理单元,这些处理单元虽然计算能力比不上CPU,但是却可以同时处理几千个像素点。像素点数据的计算相对简单,而且可以同时处理几千个像素点,图像数据用GPU来做计算就非常适合了。而怎么使用GPU呢?这就要介绍到目前使用最广泛的2D、3D矢量图形沉浸API:OpenGL了。
47+
48+
49+
4650
### Android中的OpenGL ES
4751

4852
Android中OpenGL ES的版本支持如下:
@@ -69,8 +73,8 @@ OpenGL ES的实现有2中方式:
6973
7074
- OpenGL自身是一个巨大的状态机: 描述该如何操作的所有变量的大集合
7175
- OpenGL的状态通常被称为上下文(Context)
72-
- 状态设置函数(State-changing Function)
73-
- 状态应用的函数(State-using Function)
76+
- 状态设置函数(State-changing Function): 该类函数将会改变上下文
77+
- 状态应用的函数(State-using Function): 该类函数会根据当前OpenGL的状态执行一些操作。
7478

7579
![image](https://github.com/CharonChui/Pictures/blob/master/opengl_state_machine.png?raw=true)
7680

@@ -109,7 +113,21 @@ struct object_Window_Target {
109113
}
110114
```
111115

112-
通常把OpenGL上下文比作一个大的结构体,包含很多子集。
116+
117+
但是,这样也有问题:
118+
119+
- 当前状态只有一份,如果每次显示不同的效果,都重新配置会很麻烦。
120+
- 这时候我们就需要一些小助理(对象),来帮忙记录某些状态信息,以便复用。
121+
122+
如果我们有10种子集,那就需要10个小助理(对象),而当前状态(Context,只有一份)可以通过装配这些对象来完成。
123+
124+
![image](https://github.com/CharonChui/Pictures/blob/master/opengl_zhuli.jpg?raw=true)
125+
126+
127+
通常把OpenGL上下文比作一个大的结构体,包含很多子集。
128+
129+
在OpenGL中一个对象是指一些选项的集合,它代表OpenGL状态的一个子集。
130+
比如,我们可以用一个对象来代表绘制窗口的设置,之后我们就可以设置它的大小等。
113131

114132
```C
115133
// OpenGL的状态
@@ -120,20 +138,48 @@ struct OpenGL_Context {
120138
}
121139
```
122140

123-
但是,这样也有问题:
124141

125-
- 当前状态只有一份,如果每次显示不同的效果,都重新配置会很麻烦。
126-
- 这时候我们就需要一些小助理(对象),来帮忙记录某些状态信息,以便复用。
127142

128-
如果我们有10种子集,那就需要10个小助理(对象),而当前状态(Context,只有一份)可以通过装配这些对象来完成。
143+
```c++
144+
// 创建对象
145+
unsigned int objectId = 0;
146+
glGenObject(1, &objectId);
129147

130-
![image](https://github.com/CharonChui/Pictures/blob/master/opengl_zhuli.jpg?raw=true)
148+
// 绑定对象至上下文
149+
glBindObject(GL_WINDOW_TARGET, objectId);
150+
// 设置当前绑定到GL_WINDOW_TARGET的对象的一些选项
151+
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
152+
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
153+
// 将上下文对象设回默认
154+
glBindObject(GL_WINDOW_TARGET, 0);
155+
```
156+
上面这一小段代码展示了以后使用OpenGL时常见的工作流。
157+
158+
- 我们首先创建一个对象,然后用一个id保存它的引用(实际数据被存储在后台)。
159+
- 然后我们将对象绑定至上下文的目标位置(例子中窗口对象目标的位置被定义成GL_WINDOW_TARGET)
160+
- 接下来我们设置窗口的选项。
161+
- 最后我们将目标位置的对象id设回0,解绑这个对象。
131162
163+
**设置的选项将被保存在objectId所引用的对象中,一旦我们重新绑定这个对象到GL_WINDOW_TARGET位置,这些选项就会重新生效。**
164+
165+
使用对象的一个好处是在程序中,我们不止可以定义一个对象,并设置它们的选项,每个对象都可以是不同的设置。
166+
167+
在我们执行一个使用OpenGL状态的操作的时候,只需要绑定含有需要的设置的对象即可。
132168
133169
134170
135171
### 渲染管线
136172
173+
174+
渲染管线有时也称为渲染流水线,一般由显示芯片(GPU)内部处理图形信号的并行处理单元组成。
175+
这些并行处理单元两两之间是相互独立的,在不同型号的硬件上独立处理单元的数量也有很大的差异。一般越高端型号的硬件,其中独立处理单元的数量也就越多。
176+
177+
178+
与普通应用程序通过CPU串行执行不同的是,渲染工作是通过渲染管线由多个相互独立的处理单元进行并行处理的,这种模式极大的提升了渲染效率。
179+
180+
从另一个角度看,OpenGLES中的渲染管线实际上指的是一系列绘制过程。
181+
这些过程输入的是待渲染3D物体的相关描述信息数据,经过渲染管线,输出的是一帧想要的图像。
182+
137183
在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。
138184
139185
3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程)管理的。
@@ -448,6 +494,16 @@ OpenGL中最基础且唯一的多边形就是三角形,所有更复杂的图
448494

449495
### 片段着色器或片元着色器(Fragment Shader)
450496

497+
498+
显示设备屏幕都是离散化的(由一个一个的像素组成),因此还需要将投影的结果离散化。
499+
将其分解为一个个离散化的小单元,这些小单元一版称为片元。
500+
501+
其实每个片元都对应于帧缓冲中的一个像素,之所以不直接称为像素是因为3D空间中的物体是可以相互遮挡的。而一个3D场景最终显示到屏幕上虽然是一个整体,但每个3D物体的每个图元是独立处理的。这就可能出现这样的情况,系统先处理的是位于离观察点较远的图元,其光栅化成为了一组图元,暂时送入帧缓冲的对应位置。
502+
503+
但后面继续处理离观察点较近的图元时也光栅化出了一组片元,两组片元中有对应到帧缓冲中同一个位置的,这时距离近的片元将覆盖距离远的片元(如何覆盖的检测是在深度检测阶段完成的)。
504+
505+
因此,某片元就不一定能成为最终屏幕上的像素,称为像素就不准确了,可以将其理解为候选像素。
506+
451507
使用颜色或纹理(texture)渲染图形表面的OpenGLES代码。
452508

453509

@@ -606,7 +662,7 @@ EGL为双缓冲工作模式(Double Buffer),既有一个Back Frame Buffer和一
606662

607663
6. 设置OpenGL的渲染环境
608664

609-
eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);该方法的参数意义很明确,该方法在异步线程中被调用,该线程也会被成为GL线程,一旦设定后,所有OpenGL渲染相关的操作都必须放在该线程中执行。
665+
eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);该方法的参数意义很明确,该方法在异步线程中被调用,该线程也会被称为GL线程,一旦设定后,所有OpenGL渲染相关的操作都必须放在该线程中执行。
610666

611667
通过上述操作,就完成了EGL的初始化设置,便可以进行OpenGL的渲染操作。所有EGL命令都是以egl前缀开始,对组成命令名的每个单词使用首字母大写(如eglCreateWindowSurface)。
612668

0 commit comments

Comments
 (0)