BK_*_*BK_ 5 c# delphi fonts gdi+ windows-10
与Windows 10相比,在Windows 7/8 / 8.1上进行监视时,我的应用程序显示出非常不同且非常烦人的内存占用。我将其归结为字体使用情况:
与其花费50-70 MB来枚举已安装的字体及其属性(就像该应用程序在Windows 7/8 / 8.1上所做的那样),不如花费大约500 MB来完成同一工作,这大约是它的十倍。
在谈到所需的内存时,我总是指进程的虚拟大小。
知道为什么会这样吗?似乎有些缓存在Windows 10上很流行。有什么好的解决方法?目前,我计划将所有GDI +字体处理调用映射到GDI调用,因为这些不会显示这种奇怪的行为。
(我发现Windows 10上的.NET FontFamily内存泄漏,但是没有有用的答案。)
为了缩小范围,我创建了两个示例程序。您可以运行程序并自行比较进程的VirtualSize。
C#示例仅枚举所有已安装的字体并实例化一种字体,同时适当处理非托管对象:
int i = 0;
foreach (FontFamily fontfamily in FontFamily.Families)
{
i++;
try
{
Font f = new Font(fontfamily, (float) 8.0, FontStyle.Bold);
Console.WriteLine("Created Font #{0} {1} ", i, f.Name);
f.Dispose();
f = null;
}
catch (Exception ex)
{
Console.WriteLine("Exception while creating Font {0} {1}", fontfamily.Name, ex.ToString());
}
fontfamily.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
Delphi示例更加复杂,使某些.NET内部结构更加明显。此外,您可以使用它进行不同的测试,以更出色的方式测量内存消耗。
program FontTests01;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Classes,
Windows,
System.SysUtils,
IOUtils,
WinApi.GDIPAPI,
WinApi.GDIPOBJ;
const
cFontlistFilename = 'C:\Temp\fontlist.dat';
type
TTestCallback = procedure;
function ConsoleWaitForKey: Char;
var
s: string;
begin
Readln(s);
if Length(s) > 0 then
Result := s[1]
else
Result := #0;
end;
procedure TestFontEnumeration(GetFontname: Boolean; GetAvailability: Boolean; FontNamesListFilename: string);
var
FontCollection: TGPFontCollection;
FontFamilies: array of TGPFontFamily;
FontFamily: TGPFontFamily;
FontName: string;
i, FontFamiliesRetrieved: Integer;
begin
if (FontNamesListFilename <> '') and (FileExists(FontNamesListFilename)) then
DeleteFile(FontNamesListFilename);
FontCollection := TGPInstalledFontCollection.Create;
try
SetLength(FontFamilies, FontCollection.GetFamilyCount);
ZeroMemory(@FontFamilies[0], SizeOf(TGPFontFamily) * Length(FontFamilies));
try
for i := 0 to Length(FontFamilies) - 1 do
FontFamilies[i] := TGPFontFamily.Create;
FontCollection.GetFamilies(Length(FontFamilies), FontFamilies, FontFamiliesRetrieved);
for i := 0 to FontFamiliesRetrieved - 1 do
begin
FontFamily := FontFamilies[i];
if GetFontname then
begin
FontFamily.GetFamilyName(FontName);
Write('Retrieved Font: ' + FontName + ' ');
if FontNamesListFilename <> '' then
TFile.AppendAllText(FontNamesListFilename, FontName + #13#10);
end
else
Write(IntToStr(i) + ' ');
if GetAvailability then
begin
if FontFamily.IsAvailable and FontFamily.IsStyleAvailable(FontStyleRegular) then
Writeln('available ')
else
Writeln('NOT available');
end
else
Writeln;
end;
finally
for i := 0 to Length(FontFamilies) - 1 do
FontFamilies[i].Free;
end;
finally
FontCollection.Free;
end;
end;
procedure TestFontInstantiation(GetName: Boolean; GetAvailability: Boolean; FontNamesListFilename: string);
var
List: TStringList;
FontFamily: TGPFontFamily;
FontName: string;
i: Integer;
begin
List := TStringList.Create;
try
List.LoadFromFile(FontNamesListFilename);
for I := 0 to List.Count - 1 do
begin
FontFamily := TGPFontFamily.Create(List[i]);
try
if GetName then
begin
FontFamily.GetFamilyName(FontName);
Write('Retrieved Font: ' + FontName + ' ');
end
else
Write(IntToStr(i) + ' ');
if GetAvailability then
begin
if FontFamily.IsAvailable and FontFamily.IsStyleAvailable(FontStyleRegular) then
Writeln('available ')
else
Writeln('NOT available');
end
else
Writeln;
finally
FontFamily.Free;
end;
end;
finally
List.Free;
end;
end;
function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
FontType: Integer; Data: Pointer): Integer; stdcall;
begin
Writeln(LogFont.lfFaceName);
Result := 1;
end;
procedure EnumerateFontsWithGDI;
var
DC: HDC;
LFont: TLogFont;
begin
DC := GetDC(0);
try
FillChar(LFont, sizeof(LFont), 0);
LFont.lfCharset := DEFAULT_CHARSET;
EnumFontFamiliesEx(DC, LFont, @EnumFontsProc, 0, 0);
finally
ReleaseDC(0, DC);
end;
end;
procedure TestFontEnumeration_GetFontNames_Only;
begin
TestFontEnumeration(True, False, cFontlistFilename);
end;
procedure TestFontEnumeration_GetFontAvailability_Only;
begin
TestFontEnumeration(False, True, '');
end;
procedure TestFontEnumeration_GetFontName_GetFontAvailability_Combined;
begin
TestFontEnumeration(True, True, '');
end;
procedure TestFontNames_FromFile_CreateNamedGPFontFamilies_Only;
begin
TestFontInstantiation(False, False, cFontlistFilename);
end;
procedure TestFontNames_FromFile_RetrieveFontNamesAgain;
begin
TestFontInstantiation(True, False, cFontlistFilename);
end;
procedure TestFontNames_FromFile_GetFontAvailable;
begin
TestFontInstantiation(False, True, cFontlistFilename);
end;
procedure TestFontNames_FromFile_RetrieveFontNames_GetFontAvailable_Combined;
begin
TestFontInstantiation(True, True, cFontlistFilename);
end;
procedure Test_EnumerateFontsWithGDI;
begin
EnumerateFontsWithGDI;
end;
procedure PerformTest(Caption: string; Callback: TTestCallback);
var
Key: Char;
begin
Writeln('Before Test ' + Caption + '. Hit "s" to skip, enter to continue.');
Key := ConsoleWaitForKey;
if AnsiLowerCase(Key) <> 's' then
begin
Callback;
Writeln('Test ' + Caption + ' finished. Hit a enter.');
ConsoleWaitForKey;
end
else
Writeln('Test ' + Caption + ' skipped.');
Writeln;
end;
begin
try
PerformTest('TestFontEnumeration_GetFontNames_Only', TestFontEnumeration_GetFontNames_Only);
PerformTest('TestFontEnumeration_GetFontAvailability_Only', TestFontEnumeration_GetFontAvailability_Only);
PerformTest('TestFontEnumeration_GetFontName_GetFontAvailability_Combined', TestFontEnumeration_GetFontName_GetFontAvailability_Combined);
PerformTest('TestFontNames_FromFile_CreateNamedGPFontFamilies_Only', TestFontNames_FromFile_CreateNamedGPFontFamilies_Only);
PerformTest('TestFontNames_FromFile_RetrieveFontNamesAgain', TestFontNames_FromFile_RetrieveFontNamesAgain);
PerformTest('TestFontNames_FromFile_GetFontAvailable', TestFontNames_FromFile_GetFontAvailable);
PerformTest('TestFontNames_FromFile_RetrieveFontNames_GetFontAvailable_Combined', TestFontNames_FromFile_RetrieveFontNames_GetFontAvailable_Combined);
PerformTest('Test_EnumerateFontsWithGDI', Test_EnumerateFontsWithGDI);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Writeln('Finished.');
ConsoleWaitForKey;
end.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |