DirectX怪象之二, 程序很吃CPU

简介:

学习DirectX编程的兄弟们可能经常遇到的一个情况是,程序经常莫名奇妙的占用大量的CPU资源,其实吃CPU的问题并不是DirectX程序所特有的,几乎任何程序都可能,只不过DirectX程序更加容易产生而已,总结了一下,主要有以下几个方面

没有及时释放资源

这种情况的现象多发生在程序运行的时候,也就是窗口处于active状态时,大家都知道,DX是基于COM的,这也就意味着,你需要手动释放COM对象,如果没有及时释放的话,CPU就会吃紧,尤其是当在Render函数中创建对象的时候更是如此。至于哪些需要释放,哪些不需要释放,需要视具体情况而定,这里有一个简单的方法,如果创建该对象的函数形如CreateXXX,那么基本都需要释放,这种对象一般都有一个Release方法,直接调用这个方法即可。给大家分享一个宏定义,来自于DX SDK,这个宏可以很方便的释放COM对象

#define  SAFE_RELEASE(P) if(P){ P->Release(); P = NULL;}

我们在编程时应该遵循一些好的编程习惯,这样就会避免错误发生,比如

1 对于那些只需要一次创建的对象,通通放到Render函数之外,所以我们通常设置一个函数名叫InitD3D,可以把一次性初始化的代码都放到这里。切记不可把非渲染操作放到Render函数里面,因为Render函数就是用来做渲染的,而且调用频率极高,几乎是时时刻刻都在调用,如果把其他操作资源的过程也放到这里,势必会影响效率。

2 在开发的时候尽量使用Debug版本的库,这样可以及时发现资源泄露。

没有处理窗口inactive的情况

这种情况多发生在窗口处于inactive状态时,比如被遮挡或者最小化到任务栏。先看一段Windows下的渲染框架,下面的代码逻辑很简单,有消息则处理消息,无消息则渲染,如果你使用了这段代码,那么你可以试着将窗口最小化,你将会看到CPU使用率上升一大截,为什么呢?这是由于PeekMessage的机制造成的,说到PeekMessage就不得不说GetMessage,这二者都是用于从消息队列中取得消息,不同的是,PeekMessage如果没取到消息,会立即返回0,而GetMessage如果没取到消息,则会一直等待有消息可取。也就是说PeekMessage是异步的,而GetMessage是同步的。下面的代码就是利用没有消息处理的时间进行渲染,而当窗口最小化时,PeekMessage一直取不到消息,所以程序一直在渲染,这样就占用了大量的CPU时间。

复制代码
MSG msg ;
ZeroMemory( &msg, sizeof(msg) );
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

// Get latest time
static DWORD lastTime = timeGetTime();

while (msg.message != WM_QUIT)
{
    if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) !=0)
    {
        TranslateMessage (&msg) ;
        DispatchMessage (&msg) ;
    }
    else// Render the scene if there is no message to handle
    {
        // Get current time
        DWORD currTime = timeGetTime();

        // Calculate time elapsed
        float timeDelta = (currTime - lastTime) *0.001f;

        // Render
        Render(timeDelta) ;

        // Update lastTime
        lastTime = currTime;
    }
}
复制代码

有了上面的分析,我们可以分两种情况来处理,一是程序处于active状态时,我们按照上面的方法渲染。二是程序处于inactive状态时,我们可以使用GetMessage来等待一个消息,因为此时程序不需要渲染(已经最小化了,还渲染啥呀?)。对应的代码如下

复制代码
BOOL bGotMsg;
MSG msg;
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

while( WM_QUIT != msg.message )
{
    // Use PeekMessage() if the app is active, so we can use idle time to
    // render the scene. Else, use GetMessage() to avoid eating CPU time.
    if( m_bActive )
        bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
    else
        bGotMsg = GetMessage( &msg, NULL, 0U, 0U );

    if( bGotMsg )
    {
        // Translate and dispatch the message
        if( 0== TranslateAccelerator( m_hWnd, hAccel, &msg ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
    else
    {
        // Render a frame during idle time (no messages are waiting)
        if( m_bActive )
        {
            if( FAILED( Render3DEnvironment() ) )
                SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
        }
    }
}
复制代码

下面的问题就是如何处理m_bActive这个变量了,可以响应WM_SIZE消息,SIZE_MAXHIDE表示有其他窗口最大化了,这样就意味着本窗口被完全遮挡了,SIZE_MINIMIZED表示窗口最小化了。这两种情况我们将窗口视为inactive状态。

复制代码
case  WM_SIZE:
//  Check to see if we are losing our window...
if ( SIZE_MAXHIDE == wParam  ||  SIZE_MINIMIZED == wParam )
     m_bActive 
=  FALSE;
else
     m_bActive 
=  TRUE;
break ;
复制代码

没有做场景管理

由于我对场景管理不是很熟练,所以只能简单说说,场景管理应该属于中高层次的技术,在刚学DirectX的时候,根本不会考虑这些,但是随着知识的深入,程序代码的增大,逻辑越来越复杂,模型越来越多,难免会涉及到场景管理,什么是场景管理呢,如果从渲染的角度来讲,就是区分哪些应该渲染,哪些不用渲染,就是说要提高渲染的速度,场景管理中最基本的就是Frustum剪裁,四叉树,BSP场景管理,八叉树等。

Frustum,中文翻译成视锥,视锥剪裁是最基本的场景管理,也就是只渲染在视野内的模型,其他的一律剪裁掉。

四叉树多用于地形渲染

BSP多用于室内场景管理,著名的Quake系列使用的就是BSP树

八叉树比较通用

如果你的场景中有大量的模型,而又没有做场景管理,也就意味着,一次性将所有的模型都渲染一遍,不管模型是否在视野里,这势必很浪费CPU资源。

当然,肯定还有许多其他的原因,欢迎大家补充!

 


本文转自zdd博客园博客,原文链接:http://www.cnblogs.com/graphics/archive/2012/05/07/2039569.html,如需转载请自行联系原作者

相关文章
|
数据采集 安全 Windows
解决关于Windows Defender Antivirus Service自启造成运行python程序时,Windows的cpu和内存占用过高问题
启用“关闭Windwos defender”服务解决阿里云Windows服务器的卡顿问题,并列举了网上一些错误的解决方法。
9931 2
解决关于Windows Defender Antivirus Service自启造成运行python程序时,Windows的cpu和内存占用过高问题
|
Kubernetes Java Docker
Java程序在K8S容器部署CPU和Memory资源限制相关设置
背景 在k8s docker环境中执行Java程序,因为我们设置了cpu,memory的limit,所以Java程序执行时JVM的参数没有跟我们设置的参数关联,导致JVM感知到的cpu和memory是我们k8s的work node上的cpu和memory大小。
7690 0
|
7月前
|
C++ 索引 Windows
调试实战——程序CPU占用率飙升,你知道如何快速定位吗?
程序CPU占用率飙升,你知道如何快速定位吗?
|
10月前
|
缓存 算法 Linux
程序绑定 CPU 核心
程序绑定 CPU 核心
379 0
|
数据可视化 Java Windows
windows系统启动java程序限制cpu核心数
windows系统启动java程序限制cpu核心数
441 0
windows系统启动java程序限制cpu核心数
|
Java Go 开发工具
如何排查Go 程序 CPU 占用过高问题
如何排查Go 程序 CPU 占用过高问题
1413 0
如何排查Go 程序 CPU 占用过高问题
|
Java 程序员 编译器
CPU中的程序是怎么运行起来的
CPU中的程序是怎么运行起来的
153 0
CPU中的程序是怎么运行起来的
|
程序员
CPU中的程序是怎么运行起来的(预告篇)
CPU中的程序是怎么运行起来的(预告篇)
73 0
CPU中的程序是怎么运行起来的(预告篇)
西门子S7-200 SMART如何用存储卡复位CPU出厂设置、固件升级、程序传输
上篇文章中我们学习了西门子S7-200 SMART的全局变量和局部变量以及如何编写带参数子程序并调用,本篇我们来介绍西门子S7-200 SMART使用存储卡复位CPU到出厂设置、固件升级和程序传输。S7-200 SMART CPU使用FAT32文件系统格式,支持容量为4G至32G范围内的标准商用MicroSD HC卡。
西门子S7-200 SMART如何用存储卡复位CPU出厂设置、固件升级、程序传输
|
监控 JavaScript 数据可视化
NodeJS 程序CPU占用过高
NodeJS 程序CPU占用过高
2099 0
NodeJS 程序CPU占用过高

热门文章

最新文章