surfaceflinger是什么意思作用,怎么这么耗电

Android4.4深入浅出之SurfaceFlinger总体结构
4.4 GUI框架之SurfaceFlinger
Android GUI框架:
SurfaceFlinger:每当用户程序刷新UI的时候,会中介BufferQueue申请一个buffer(dequeueBuffer),然后把UI的信息填入,丢给SurfaceFlinger,SurfaceFlinger通过计算多重计算合成visibleRegion之后,丢给openGL层处理,处理之后送到显示器display上显示。
根据整个Android系统的GUI设计理念,我们不难猜想到至少需要两种本地窗口:
面向管理者(SurfaceFlinger)
既然SurfaceFlinger扮演了系统中所有UI界面的管理者,那么它无可厚非地需要直接或间接地持有“本地窗口”,这个窗口就是FramebufferNativeWindow
面向应用程序
这类窗口是Surface(这里和以前版本出入比较大,之前的版本本地窗口是SurfaceTextureClient)
第二种窗口是能直接显示在终端屏幕上的――它使用了帧缓冲区,而第一种Window实际上是从内存缓冲区分配的空间。当系统中存在多个应用程序时,这能保证它们都可以获得一个“本地窗口”,并且这些窗口最终也能显示到屏幕上――SurfaceFlinger会收集所有程序的显示需求,对它们做统一的图像混合操作。
SurfaceFlinger和BufferQueue
一个UI完全显示到diplay的过程,SurfaceFlinger扮演着重要的角色但是它的职责是“Flinger”,即把系统中所有应用程序的最终的“绘图结果”进行“混合”,然后统一显示到物理屏幕上,而其他方面比如各个程序的绘画过程,就由其他东西来担任了。这个光荣的任务自然而然地落在了BufferQueue的肩膀上,它是每个应用程序“一对一”的辅导老师,指导着UI程序的“画板申请”、“作画流程”等一系列细节。下面的图描述了这三者的关系:
虽说是三者的关系,但是他们所属的层却只有两个,app属于java层,BufferQueue/SurfaceFlinger属于native层。也就是说BufferQueue也是隶属SurfaceFlinger,所有工作围绕SurfaceFlinger展开。
这里IGraphicBufferProducer就是app和BufferQueue重要桥梁,GraphicBufferProducer承担着单个应用进程中的UI显示需求,与BufferQueue打交道的就是它。它的工作流程如下:
BpGraphicBufferProducer是GraphicBufferProducer在客户端这边的代理对象,负责和SF交互,GraphicBufferProducer通过gbp(IGraphicBufferProducer类对象)向BufferQueue获取buffer,然后进行填充UI信息,当填充完毕会通知SF,SF知道后就对该Buffer进行下一步操作。典型的生产-消费者模式。
接下来具体说明客户端(producer)和服务端SurfaceFlinger(consumer)工作的模式:
首先这里的buffer是共享缓冲区,故肯定会涉及到互斥锁,所以buffer的状态也会有多种,一般的buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个流程,如右图:
BufferQueue
可以认为BufferQueue是一个服务中心,其它两个owner必须要通过它来管理buffer。比如说当producer想要获取一个buffer时,它不能越过BufferQueue直接与consumer进行联系,反之亦然。
生产者就是“填充”buffer空间的人,通常情况下当然就是应用程序。因为应用程序不断地刷新UI,从而将产生的显示数据源源不断地写到buffer中。当Producer需要使用一块buffer时,它首先会向中介BufferQueue发起dequeue申请,然后才能对指定的缓冲区进行操作。这种情况下buffer就属于producer一个人的了,它可以对buffer进行任何必要的操作,而其它owner此刻绝不能擅自插手。
当生产者认为一块buffer已经写入完成后,它进一步调用BufferQueue的queue。从字面上看这个函数是“入列”的意思,形象地表达了buffer此时的操作――把buffer归还到BufferQueue的队列中。一旦queue成功后,owner也就随之改变为BufferQueue了
消费者是与生产者相对应的,它的操作同样受到BufferQueue的管控。当一块buffer已经就绪后,Consumer就可以开始工作了。这里需要特别留意的是,从各个对象所扮演的角色来看,BufferQueue是中介机构,属于服务提供方;Producer属于buffer内容的产出方,它对缓冲区的操作是一个“主动”的过程;反之,Consumer对buffer的处理则是“被动”的、“等待式”的――它必须要等到一块buffer填充完成后才能做工作。在这样的模型下,我们怎么保证Consumer可以及时的处理buffer呢?换句话说,当一块buffer数据ready后,应该怎么告知Consumer来操作呢?
仔细观察的话,可以看到BufferQueue里还同时提供了一个特别的类,名称为ProxyConsumerListener,其中的函数接口包括:
classProxyConsumerListener : public BnConsumerListener {
//省略构造函数
virtual void onFrameAvailable();/*当一块buffer可以被消费时,这个函数会被调用,特别注意此时没有共享锁的保护*/
virtual voidonBuffersReleased();/*BufferQueue通知consumer它已经释放其slot中的一个或多个 GraphicBuffer引用*/
wpmConsumerL
这样子就很清楚了,当有一帧数据准备就绪后,BufferQueue就会调用onFrameAvailable()来通知Consumer进行消费。
BufferQueue和SurfaceFlinger之间的通信模式如下:
也是有一对BpGraphicBufferConsumer/BnGraphicBufferConsumer支持他们之间的信息传输。
具体分析BufferQueue
首先说明一下BufferQueue的类关系:
下面是BufferQueue中的核心函数分析:
核心成员函数
setBufferCount
setBufferCount updates the
number of available buffer slots.
requestBuffer
requestBuffer returns the
GraphicBuffer for slot N.
dequeueBuffer
dequeueBuffer gets the next
buffer slot index for the producer to use.
queueBuffer
queueBuffer returns a filled
buffer to the BufferQueue.
cancelBuffer
cancelBuffer returns a
dequeued buffer to the BufferQueue
acquireBuffer
acquireBuffer attempts to
acquire ownership of the next pending buffer BufferQueue.
releaseBuffer
releaseBuffer releases a
buffer slot from the consumer back to the BufferQueue.
BufferQueue是IGraphicBufferProducer和IGraphicBufferConsumer的具体实现,用户在请求和SurfaceFlinger连接的过程中会请求SF创建一个Layer,IGraphicBufferProducer就是在这个过程中获取一个BufferQueue对象,又转化成IGraphicBufferProducer类对象,是为了进一步和BufferQueue进行交互,下面是关键代码:
status_t SurfaceFlinger::createNormalLayer(constsp& client,
const String8& name, uint32_t w,uint32_t h, uint32_t flags, PixelFormat& format,
sp* handle, sp*gbpsp* outLayer)
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
case PIXEL_FORMAT_OPAQUE:
#ifdefNO_RGBX_8888
if (format == PIXEL_FORMAT_RGBX_8888)
format = PIXEL_FORMAT_RGBA_8888;
*outLayer = new Layer(this, client, name,w, h, flags);
status_t err =(*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp =(*outLayer)->getBufferQueue();
ALOGE_IF(err, "createNormalLayer()failed (%s)", strerror(-err));
下面是getBufferQueue的实现,很简单,获取BufferQueue对象:
spLayer::getBufferQueue() const {
return mBufferQ
IGraphicBufferProducer是个接口类,它的实现必然在子类BpGraphicBufferProducer中实现,我们来看下这个类:
classBpGraphicBufferProducer : public BpInterface
BpGraphicBufferProducer(constsp& impl)
:BpInterface(impl)
virtual status_t requestBuffer(intbufferIdx, sp* buf) {
Parcel data,
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
status_t result =remote()->transact(REQUEST_BUFFER, data,&reply);
if (result != NO_ERROR) {
bool nonNull = reply.readInt32();
if (nonNull) {
*buf = new GraphicBuffer();
reply.read(**buf);
result = reply.readInt32();
virtual status_t dequeueBuffer(int*buf, sp* fence, bool async,
uint32_t w, uint32_t h, uint32_tformat, uint32_t usage) {
Parcel data,
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(async);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
data.writeInt32(usage);
status_t result = remote()->transact(DEQUEUE_BUFFER, data,&reply);
if (result != NO_ERROR) {
*buf = reply.readInt32();
bool nonNull = reply.readInt32();
if (nonNull) {
*fence = new Fence();
reply.read(**fence);
result = reply.readInt32();
virtual status_t queueBuffer(intbuf,
const QueueBufferInput& input,QueueBufferOutput* output) {
Parcel data,
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(buf);
data.write(input);
status_t result = remote()->transactQUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
memcpy(output,reply.readInplace(sizeof(*output)), sizeof(*output));
result = reply.readInt32();
省去了一些成员函数,只贴出关键成员函数,首先这里的dequeueBuffer和queueBuffer并非真正对Buffer进行操作,留意红色部分,会发现他只是发出一个“消息”通知接收方要去
Dequeue一个Buffer或queue一个Buffer。相对应的BnGraphicBufferProducer来接收消息。
BnGraphicBufferProducer中的onTransact负责这件事:
status_tBnGraphicBufferProducer::onTransact(
uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)
switch(code) {
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async
= data.readInt32();
uint32_t w
= data.readInt32();
uint32_t h
=data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage
= data.readInt32();
int result = dequeueBuffer(&buf, &fence, async, w, h,format, usage);
reply->writeInt32(buf);
reply->writeInt32(fence !=NULL);
if (fence != NULL) {
reply->write(*fence);
reply->writeInt32(result);
return NO_ERROR;
case QUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int buf = data.readInt32();
QueueBufferInput input(data);
QueueBufferOutput* const output =
reinterpret_cast(
reply->writeInplace(sizeof(QueueBufferOutput)));
status_t result = queueBuffer(buf, input, output);
reply->writeInt32(result);
return NO_ERROR;
return BBinder::onTransact(code, data,reply, flags);
省略了一些分支,留意红色部分才发现这里调用了dequeueBuffer和queueBuffer,
它们的实现在BufferQueue中,这里才真正踏足到BufferQueue领域中。到这里客户端和BufferQueue建立联系,接下去的事就是BufferQueue内部处理的事了,BufferQueue和SuefaceFlinger之间的关系也如此。
SurfaceFlinger处理buffer
这里先用2张图来介绍下SurfaceFlinger的整个消息处理机制和工作流程:
更具体的代码流程之前有经过分析。
这里继续下去对handleMessageRefresh分析,这是SuefaceFlinger的核心处理函数。
voidSurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
preComposition();
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition();
postComposition();
//………省略
preComposition();预先准备“合成物“就是客户端那边传来的UI信息的buffer;
rebuildLayerStacks();在每一个screen上重建可见区域;
setUpHWComposer();初始化一个硬件容器;
doDebugFlashRegions();这个函数一般进去就返回来了;
doComposition();实质的合成过程,并且合成完的BUFFER由opengl es处理,处理之后由postFramebuffer()送到display上显示;
这里重点研究doComposition()
voidSurfaceFlinger::doComposition() {
ATRACE_CALL();
const bool repaintEverything =android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy<mDisplays.size(); dpy++) {
const sp&hw(mDisplays[dpy]);
if (hw->canDraw()) {
// transform the dirty region intothis screen&#39;s coordinate space
const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
// repaint the framebuffer (ifneeded)
doDisplayComposition(hw, dirtyRegion);
hw->dirtyRegion.clear();
hw->flip(hw->swapRegion);
hw->swapRegion.clear();
// inform the h/w that we&#39;re donecompositing
hw->compositionComplete();
postFramebuffer();
doDisplayComposition(hw, dirtyRegion);负责渲染的核心函数它的走向是:
doDisplayComposition-> doComposeSurfaces->draw->onDraw->drawWithOpenGL.一直走到OPENGL层。Opengl贴完图之后,调用了flip函数,在这里跟之前版本有很大出入,之前版本flip是在postFramebuffer中的,而且函数内容也做了很大的改变,只是计数加一。
在这里说明一下,UI显示是双缓冲机制,每当画完一个buffer需要flip一下,也就是交换。但在这个版本已经融合到postFramebuffer中:
贴出关键代码
r = mit();
成员变量hwc是在DisplayHardware::init中生成的一个HWComposer对象。只要HWC_HARDWARE_MODULE_ID模块可以正常加载,且hwc_open能打开hwc_composer_device设备,那么initCheck()就返回NO_ERROR,否则就是NO_INIT。
此时我们通过HWComposer::commit来执行flip,这个函数直接调用如下硬件接口:
mHwc->set(mHwc, mNumDisplays, mLists);
set()和后面的eglSwapBuffers是基本等价的,原型如下:
int (*set)(struct hwc_composer_device*dev,hwc_display_t dpy,
hwc_layer_list_t* list);
其中最后一个list必须与最近一次的prepare()所用列表完全一致。假如list为空或者列表数量为0的话,说明SurfaceFlinger已经利用OpenGL
ES做了composition,此时set就和eglSwapBuffers一样。当list不为空,且layer的compositionType
== HWC_OVERLAY,那么HWComposer需要进行硬件合成。
如果成功执行的话,set返回0,否则就是HWC_EGL_ERROR。
如果没成功的话,后面还有一句:
hw->hwcSwapBuffers();
作用也是跟flip一样。它的函数走向是:
hwcSwapBuffers->eglSwapBuffers->swapBuffers->advanceFrame-> fbPost->post。
一旦交换完毕就顺着这个走向抛给底层display去显示。
这里我们主要研究swapBuffers这个函数:
EGLBooleanegl_window_surface_v2_t::swapBuffers()
//………….
nativeWindow->queueBuffer(nativeWindow,buffer, -1);
// dequeue a new buffer
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd)== NO_ERROR) {
sp fence(new Fence(fenceFd));
if(fence->wait(Fence::TIMEOUT_NEVER)) {
nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
return setError(EGL_BAD_ALLOC,EGL_FALSE);
//。。。。。。
这和我一开始的那张图的流程是一致的――通过queueBuffer来入队,然后通过dequeueBuffer重新申请一个buffer以用于下一轮的刷新。
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。后使用快捷导航没有帐号?
只需一步,快速开始
查看: 747|回复: 0
在线时间0 小时经验值111 最后登录注册时间帖子阅读权限40UID
高中生, 积分 111, 距离下一级还需 89 积分
TA的每日心情衰 09:29签到天数: 7 天[LV.3]偶尔看看II
G币5 最后登录注册时间
马上注册,结交更多机友,下载更多应用,让你轻松玩转手机。
已有帐号?   下载游戏和软件,请【】进入机锋市场!
xt907.发现surfaceflinger这个玩意太费电,我查了下,好像是界面,或者是显示,想问下怎么降低就个surfaceflinger的耗电量呢
Powered byAndroid2.2,2.3,4.0 中怎么使用GPU硬件加速原理 和游戏3D性能的提升_JAVA中的Stack跟Heap_Jedis运用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
Android2.2,2.3,4.0 中怎么使用GPU硬件加速原理 和游戏3D性能的提升
JAVA中的Stack跟Heap
Jedis运用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】
Android2.2,2.3,4.0 中怎么使用GPU硬件加速原理 和游戏3D性能的提升
Android2.2,2.3,4.0 中如何使用GPU硬件加速原理 和游戏3D性能的提升/viewthread.php?tid=&bbsid=648
http://blog.csdn.net/martingang/article/details/8142120
/aokikyon/item/70e973d043bad21c21e2500d
资料来自网络收集。
1.名词解释
GPU:GraphicProcessing Unit (图形处理器)
OpenGL:OpenGraphic Library 定义了一个跨编程语言、跨平台的编程接口的规格,不同厂商会有不同的实现方法,它主要用于三维图象(二维的亦可)绘制。
SurfaceFlinger:Android中负责Surface之间叠加、混合操作的动态库
Skia:Android中的2D图形库
libagl:Android中通过软件方法实现的一套OpenGL动态库
libhgl:为区别libagl,自定义的一种叫法。特指GPU厂商提供的硬件实现的OpenGL
composition:特指SurfaceFlinger对各个Surface之间的叠加、混合操作
render:特指使用OpenGL动态库进行3D渲染
copybit:Android使用2D引擎来加速图形操作(主要是Surface之间的composition操作)的一种技术,对应着一个或几个动态库。
pmem:Android特有驱动,从linux内核中reserve物理连续内存,可以为2d、3d引擎、vpu等设备分配物理连续内存。2 3D、2D引擎在Android中的使用方法2.1Android如何使用2D、3D引擎
Android在启动后,会在运行时根据配置文件加载OpenGL(libagl & libhgl)的实现,如果有libhgl实现,默认使用libhgl实现,否则使用libagl实现。
Android OpenGL动态库使用方法:
1. 判断是否含有egl.cfg文件,如果没有在加载libagl
2. 如果有egl.cfg文件,则解析egl.cfg文件,根据egl.cfg文件加载对应libhgl和libagl
3. 分别解析libagl和libhgl,获取libagl和libhgl中标准OpenGL函数的函数地址(函数指针)
4. 系统在执行过程中,会通过函数指针调用到libagl或者libhgl中去,从而实现图形的绘制。
OpenGL在Android中两个作用:
1. 用于Surface的composition操作。
SurfaceFlinger会调用到OpenGL中,通过libagl或者libhgl做Surface的组合、叠加操作。
2. 用于图形图像的渲染
Android framework会对OpenGL实现进行java层次的简单封装,在java应用程序中对OpenGL的调用最终会调用到libagl或者libhgl中去。
很多第三方游戏、3D图库、某些launcher会使用OpenGL实现比较炫丽UI的特效。
Copybit在Android中的作用
Copybit在Android中主要用于Surface的composition操作。
Skia在Android中的作用
Skia是Android的2D图形库,用于绘制文字、几何图形、图像等。
Skia的设备后端:Raster、OpenGL、PDF2.2 使用GPU硬件加速需要做的工作
1. Linux内核方面:
1.1添加GPU驱动支持,以模块方式编译GPU驱动,Android启动时加载内核模块。
1.2添加PMEM支持,预留内存供GPU使用
2. Android方面:
2.1添加copybit HAL
我们使用copybit调用2D engine对surface composition进行硬件加速。这样可能会达到更大的性能提升效果(比起使用3Dengine)。
2.2修改gralloc
gralloc负责显存等的分配,以及对framebuffer操作。如果使用copybit,必须修改gralloc
2.3修改libagl
如果使用copybit,必须修改libagl,对libagl做部分hack,使之能够调用到copybit。
2.4修改surfaceflinger
如果使用 copybit可能需要做部分修改3D性能提升(有很多人问,这样会不会增加耗电什么的,我觉得只会减少耗电,毕竟3D本来就是gpu的强项,之所以系统还会调用cpu,是为了保证兼容性。本帖士只会让系统优先调用gpu)用Root Explorer打开 /system/lib/egl长按并选择打开egl.cfg文件会有一下:0 0 android0 1 adreno200删去第一行,使之成为: 0 1 adreno200这样更改之后,3D游戏明显流畅,象限3D跑分轻松上700,其中星球的那一项可以达到60fps。原理说明:本文件的作用是帮助系统选择“在某些3D应用时,使用cpu还是gpu来解码”,0为是,1为否。即每行语法如下: 情况A是否调用 情况B是否调用 调用什么可以看到,原设置是,在情况A下,cpu和gpu都可以被选择,而情况B下则选择cpu。问题就出在这个情况A,很多软件会默认选择cpu,可能因为它在第一行,所以我们要更改这一设定。更改有三种方法,都是在xda上被广泛认可的:1.删除cpu的解码包(同文件夹下的libGLES_android.so),这个是xda上最开始出现的做法,很野蛮,可能会出问题,强烈不推荐。2.将第一行的两个0改成两个1,使之成为:0 0 android0 1 adreno200这样就迫使软件使用gpu。那为什么不改成1 0呢?因为大神们还没搞清楚情况A和情况B的对应关系。3.如本人所述,直接删除第一行。这样,软件默认使用gpu,因为没有cpu的描述,在gpu失败的情况下,系统还是会继续使用cpu。
JAVA中的Stack跟Heap
JAVA中的Stack和Heap在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题。
的内存分为两部分:Stack和Heap。
(栈)是JVM的内存指令区。Stack管理很简单,push一定长度字节的数据或者指
令,Stack指针压栈相应的字节位移;pop一定字节长度数据或者指令,Stack指针弹栈。Stack的速度很快,管理很简单,并且每次操作的数据或
者指令字节长度是已知的。所以Java 基本数据类型,Java 指令代码,常量都保存在Stack中。
(堆)是JVM的内存数据区。Heap
的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在Heap
中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在
Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap
中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。
由于Stack的内存管理是顺序分配的,而且定长,不存在内存回收问题;而Heap
则是随机分配内存,不定长度,存在内存分配和回收的问题;因此在JVM中另有一个GC进程,定期扫描Heap
,它根据Stack中保存的4字节对象地址扫描Heap ,定位Heap 中这些对象,进行一些优化(例如合并空闲内存块什么的),并且假设Heap
中没有扫描到的区域都是空闲的,统统refresh(实际上是把Stack中丢失了对象地址的无用对象清除了),这就是垃圾收集的过程;关于垃圾收集的更
深入讲解请参考bitscn之前的文章《JVM内存模型及垃圾收集策略解析》。
JVM的体系结构
我们首先要搞清楚的是什么是数据以及什么是指令。然后要搞清楚对象的方法和对象的属性分别保存在哪里。
1)方法本身是指令的操作码部分,保存在Stack中;
2)方法内部变量作为指令的操作数部分,跟在指令的操作码之后,保存在Stack中(实际上是简单类型保存在Stack中,对象类型在Stack中保存地址,在Heap 中保存值);上述的指令操作码和指令操作数构成了完整的Java 指令。
3)对象实例包括其属性值作为数据,保存在数据区Heap 中。
非静态的对象属性作为对象实例的一部分保存在Heap 中,而对象实例必须通过Stack中保存的地址指针才能访问到。因此能否访问到对象实例以及它的非静态属性值完全取决于能否获得对象实例在Stack中的地址指针。
非静态方法和静态方法的区别:
非静态方法
有一个和静态方法很重大的不同:非静态方法有一个隐含的传入参数,该参数是JVM给它的,和我们怎么
写代码无关,这个隐含的参数就是对象实例在Stack中的地址指针。因此非静态方法(在Stack中的指令代码)总是可以找到自己的专用数据(在Heap
中的对象属性值)。当然非静态方法也必须获得该隐含参数,因此非静态方法在调用前,必须先new一个对象实例,获得Stack中的地址指针,否则JVM将
无法将隐含参数传给非静态方法。
无此隐含参数,因此也不需要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法即可被调用。当然此时静态方法是存取不到Heap 中的对象属性的。
总结一下该过程:当一个class文件被ClassLoader load进入JVM后,方法指令保存在Stack中,此时Heap
区没有数据。然后程序技术器开始执行指令,如果是静态方法,直接依次执行指令代码,当然此时指令代码是不能访问Heap
数据区的;如果是非静态方法,由于隐含参数没有值,会报错。因此在非静态方法执行前,要先new对象,在Heap
中分配数据,并把Stack中的地址指针交给非静态方法,这样程序技术器依次执行指令,而指令代码此时能够访问到Heap 数据区了。
静态属性和动态属性
前面提到对象实例以及动态属性都是保存在Heap 中的,而Heap
必须通过Stack中的地址指针才能够被指令(类的方法)访问到。因此可以推断出:静态属性是保存在Stack中的,而不同于动态属性保存在Heap
中。正因为都是在Stack中,而Stack中指令和数据都是定长的,因此很容易算出偏移量,也因此不管什么指令(类的方法),都可以访问到类的静态属
性。也正因为静态属性被保存在Stack中,所以具有了全局属性。
在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。
1) Heap是 Stack的一个子集。
2) Stack存取速度仅次于寄存器,Stack里面的数据可共享,但是其中数据的大小和生存期必须在运行前确定。
3) Heap是运行时可动态分配的数据区,从速度看比Stack慢,Heap里面的数据不共享,大小和生存期都可以在运行时再确定。
4) new关键字 是运行时在Heap里面创建对象。每new一次都一定会创建新对象,因为堆数据不共享。
Eg: String str1= new String("abc");
String str2= "abc";
str1是在Heap里面创建的对象。
str2是指向Stack里面值为“abc”的引用变量,语句(2)的执行,首先会创建引用变量str2, 再查找Stack里面有没有“abc”,有则将 str2指向 “abc”,没有则在Stack里面创建一个“abc”,再将str2指向“abc”。
Jedis运用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】
Jedis使用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】前段时间细节的了解了Jedis的使用,Jedis是redis的java版本的客户端实现。本文做个总结,主要分享如下内容:
【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】好了,一个一个来。一、 Pipeline官方的说明是:starts a pipeline,which is a very efficient way to send lots of command and read all the responses when you finish sending them。简单点说pipeline适用于批处理。当有大量的操作需要一次性执行的时候,可以用管道。示例:Jedis jedis = new Jedis(String, int);Pipeline p = jedis.pipelined();p.set(key,value);//每个操作都发送请求给redis-serverp.get(key,value);p.sync();//这段代码获取所有的response
这里我进行了20w次连续操作(10w读,10w写),不用pipeline耗时:187242ms,用pipeline耗时:1188ms,可见使用管道后的性能上了一个台阶。看了代码了解到,管道通过一次性写入请求,然后一次性读取响应。也就是说jedis是:request response,request response,...;pipeline则是:request request... response response的方式。这样无需每次请求都等待server端的响应。二、 跨jvm的id生成器 谈到这个话题,首先要知道redis-server端是单线程来处理client端的请求的。这样来实现一个id生成器就非常简单了,只要简单的调用jdeis.incr(key);就搞定了。你或许会问,incr是原子操作吗,能保证不会出现并发问题吗,前面说过,server端是单线程处理请求的。三、 【跨jvm的锁实现【watch】【multi】】首先说下这个问题的使用场景,有些时候我们业务逻辑是在不同的jvm进程甚至是不同的物理机上的jvm处理的。这样如何来实现不同jvm上的同步问题呢,其实我们可以基于redis来实现一个锁。具体事务和监听请参考文章:redis学习笔记之事务 暂时找到三种实现方式:1. 通过jedis.setnx(key,value)实现
import java.util.R
import mons.pool.impl.GenericObjectPool.Cimport redis.clients.jedis.Jimport redis.clients.jedis.JedisPimport redis.clients.jedis.T/** * @author Teaey */public class RedisLock {
//加锁标志
public static final String LOCKED = "TRUE";
public static final long ONE_MILLI_NANOS = 1000000L;
//默认超时时间(毫秒)
public static final long DEFAULT_TIME_OUT = 3000;
public static JedisP
public static final Random r = new Random();
//锁的超时时间(秒),过期删除
public static final int EXPIRE = 5 * 60;
pool = new JedisPool(new Config(), "host", 6379);
//锁状态标志
private boolean locked = false;
public RedisLock(String key) {
this.key =
this.jedis = pool.getResource();
public boolean lock(long timeout) {
long nano = System.nanoTime();
timeout *= ONE_MILLI_NANOS;
while ((System.nanoTime() - nano) & timeout) {
if (jedis.setnx(key, LOCKED) == 1) {
jedis.expire(key, EXPIRE);
locked = true;
// 短暂休眠,nano避免出现活锁
Thread.sleep(3, r.nextInt(500));
} catch (Exception e) {
return false;
public boolean lock() {
return lock(DEFAULT_TIME_OUT);
// 无论是否加锁成功,必须调用
public void unlock() {
if (locked)
jedis.del(key);
} finally {
pool.returnResource(jedis);
2. 通过事务(multi)实现由于采纳第一张方法,第二种跟第三种实现只贴了关键代码,望谅解。^_^
public boolean lock_2(long timeout) {
long nano = System.nanoTime();
timeout *= ONE_MILLI_NANOS;
while ((System.nanoTime() - nano) & timeout) {
Transaction t = jedis.multi();
// 开启事务,当server端收到multi指令
// 会将该client的命令放入一个队列,然后依次执行,知道收到exec指令
t.getSet(key, LOCKED);
t.expire(key, EXPIRE);
String ret = (String) t.exec().get(0);
if (ret == null || ret.equals("UNLOCK")) {
return true;
// 短暂休眠,nano避免出现活锁
Thread.sleep(3, r.nextInt(500));
} catch (Exception e) {
return false;
3. 通过事务+监听实现
public boolean lock_3(long timeout) {
long nano = System.nanoTime();
timeout *= ONE_MILLI_NANOS;
while ((System.nanoTime() - nano) & timeout) {
jedis.watch(key);
// 开启watch之后,如果key的值被修改,则事务失败,exec方法返回null
String value = jedis.get(key);
if (value == null || value.equals("UNLOCK")) {
Transaction t = jedis.multi();
t.setex(key, EXPIRE, LOCKED);
if (t.exec() != null) {
return true;
jedis.unwatch();
// 短暂休眠,nano避免出现活锁
Thread.sleep(3, r.nextInt(500));
} catch (Exception e) {
return false;
最终采用第一种实现,因为加锁只需发送一个请求,效率最高。四、 【redis分布式】
最后一个话题,jedis的分布式。在jedis的源码里发现了两种hash算法(MD5,MURMUR Hash(默认)),也可以自己实现redis.clients.util.Hashing接口扩展。
List&JedisShardInfo& hosts = new ArrayList&JedisShardInfo&();
JedisShardInfo host1 = new JedisShardInfo("", );
JedisShardInfo host2 = new JedisShardInfo("", );
hosts.add(host1);
hosts.add(host2);
ShardedJedis jedis = new ShardedJedis(hosts);
jedis.set("key", "");
另外写博客真费力。。。
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:

我要回帖

更多关于 flinger是什么意思 的文章

 

随机推荐