我正试图在delphi中构建一个允许用户使用谷歌地图的系统。这一切都很好,但我注意到,每次创建一个新的TWebBrowser对象并加载处理谷歌地图的javascript时,都会生成许多新的线程。
我的问题是,即使网络浏览器被破坏了(而且它肯定被破坏了),创建的线程仍然存在。我设计这个程序的运行时间很长,谷歌地图的打开和关闭会发生很多次,因此,过了一段时间,生成了很多线程,但没有终止,以至于程序速度急剧下降。
有没有办法自己销毁这些线程,或者我做错了什么,导致线程持续存在?
我的程序基于以下代码:
const
HTMLStr: AnsiString =
'<html> '+
'<head> '+
'<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" /> '+
'<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"> </script> '+
'<script type="text/javascript"> '+
''+
''+
' var geocoder; '+
' var map; '+
' var trafficLayer;'+
' var bikeLayer;'+
' var markersArray = [];'+
''+
''+
' function initialize() { '+
' geocoder = new google.maps.Geocoder();'+
' var latlng = new google.maps.LatLng(40.714776,-74.019213); '+
' var myOptions = { '+
' zoom: 13, '+
' center: latlng, '+
' mapTypeId: google.maps.MapTypeId.ROADMAP '+
' }; '+
' map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); '+
' trafficLayer = new google.maps.TrafficLayer();'+
' bikeLayer = new google.maps.BicyclingLayer();'+
' map.set("streetViewControl", false);'+
' } '+
''+
''+
' function codeAddress(address) { '+
' if (geocoder) {'+
' geocoder.geocode( { address: address}, function(results, status) { '+
' if (status == google.maps.GeocoderStatus.OK) {'+
' map.setCenter(results[0].geometry.location);'+
' PutMarker(results[0].geometry.location.lat(), results[0].geometry.location.lng(), results[0].geometry.location.lat()+","+results[0].geometry.location.lng());'+
' } else {'+
' alert("Geocode was not successful for the following reason: " + status);'+
' }'+
' });'+
' }'+
' }'+
''+
''+
' function GotoLatLng(Lat, Lang) { '+
' var latlng = new google.maps.LatLng(Lat,Lang);'+
' map.setCenter(latlng);'+
' PutMarker(Lat, Lang, Lat+","+Lang);'+
' }'+
''+
''+
'function ClearMarkers() { '+
' if (markersArray) { '+
' for (i in markersArray) { '+
' markersArray[i].setMap(null); '+
' } '+
' } '+
'} '+
''+
' function PutMarker(Lat, Lang, Msg) { '+
' var latlng = new google.maps.LatLng(Lat,Lang);'+
' var marker = new google.maps.Marker({'+
' position: latlng, '+
' map: map,'+
' title: Msg+" ("+Lat+","+Lang+")"'+
' });'+
' markersArray.push(marker); '+
' }'+
''+
''+
' function TrafficOn() { trafficLayer.setMap(map); }'+
''+
' function TrafficOff() { trafficLayer.setMap(null); }'+
''+''+
' function BicyclingOn() { bikeLayer.setMap(map); }'+
''+
' function BicyclingOff(){ bikeLayer.setMap(null);}'+
''+
' function StreetViewOn() { map.set("streetViewControl", true); }'+
''+
' function StreetViewOff() { map.set("streetViewControl", false); }'+
''+
''+'</script> '+
'</head> '+
'<body onload="initialize()"> '+
' <div id="map_canvas" style="width:100%; height:100%"></div> '+
'</body> '+
'</html> ';
procedure TfrmMain.FormCreate(Sender: TObject);
var
aStream : TMemoryStream;
begin
WebBrowser1.Navigate('about:blank');
if Assigned(WebBrowser1.Document) then
begin
aStream := TMemoryStream.Create;
try
aStream.WriteBuffer(Pointer(HTMLStr)^, Length(HTMLStr));
//aStream.Write(HTMLStr[1], Length(HTMLStr));
aStream.Seek(0, soFromBeginning);
(WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(aStream));
finally
aStream.Free;
end;
HTMLWindow2 := (WebBrowser1.Document as IHTMLDocument2).parentWindow;
end;
end;
procedure TfrmMain.ButtonGotoLocationClick(Sender: TObject);
begin
HTMLWindow2.execScript(Format('GotoLatLng(%s,%s)',[Latitude.Text,Longitude.Text]), 'JavaScript');
end;
procedure TfrmMain.ButtonClearMarkersClick(Sender: TObject);
begin
HTMLWindow2.execScript('ClearMarkers()', 'JavaScript')
end;
procedure TfrmMain.ButtonGotoAddressClick(Sender: TObject);
var
address : string;
begin
address := MemoAddress.Lines.Text;
address := StringReplace(StringReplace(Trim(address), #13, ' ', [rfReplaceAll]), #10, ' ' , [rfReplaceAll]);
HTMLWindow2.execScript(Format('codeAddress(%s)',[QuotedStr(address)]), 'JavaScript');
end;
procedure TfrmMain.CheckBoxStreeViewClick(Sender: TObject);
begin
if CheckBoxStreeView.Checked then
HTMLWindow2.execScript('StreetViewOn()', 'JavaScript')
else
HTMLWindow2.execScript('StreetViewOff()', 'JavaScript');
end;
procedure TfrmMain.CheckBoxBicyclingClick(Sender: TObject);
begin
if CheckBoxBicycling.Checked then
HTMLWindow2.execScript('BicyclingOn()', 'JavaScript')
else
HTMLWindow2.execScript('BicyclingOff()', 'JavaScript');
end;
procedure TfrmMain.CheckBoxTrafficClick(Sender: TObject);
begin
if CheckBoxTraffic.Checked then
HTMLWindow2.execScript('TrafficOn()', 'JavaScript')
else
HTMLWindow2.execScript('TrafficOff()', 'JavaScript');
end;
end.
程序使用一个基本的析构函数,将HTMLWindow设置为about:black。提前感谢
这并不能回答这个问题,它只是简化了要模拟的问题。
查看每次单击按钮后运行的线程数。它使用Simple Google Maps example
,所以问题甚至不在javascript部分。
neneneba单元1-包含主窗体,其中只有一个带有OnClick事件处理程序的按钮
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, PsAPI, TlHelp32, Unit2;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetThreadCount(const APID: Cardinal): Integer;
var
NextProc: Boolean;
ProcHandle: THandle;
ThreadEntry: TThreadEntry32;
begin
Result := 0;
ProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (ProcHandle <> INVALID_HANDLE_VALUE) then
try
ThreadEntry.dwSize := SizeOf(ThreadEntry);
NextProc := Thread32First(ProcHandle, ThreadEntry);
while NextProc do
begin
if ThreadEntry.th32OwnerProcessID = APID then
Inc(Result);
NextProc := Thread32Next(ProcHandle, ThreadEntry);
end;
finally
CloseHandle(ProcHandle);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ModalForm: TForm2;
begin
ModalForm := TForm2.Create(nil);
try
ModalForm.ShowModal;
finally
ModalForm.Free;
end;
ShowMessage('Thread count: ' +
IntToStr(GetThreadCount(GetCurrentProcessId)));
end;
end.
neneneba Unit2-包含带有TWebBrowser的表单和表单的OnCreate事件处理程序
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, OleCtrls, SHDocVw, ActiveX;
type
TForm2 = class(TForm)
WebBrowser1: TWebBrowser;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
const
HTMLString: AnsiString =
'<!DOCTYPE html>' +
'<html>' +
' <head>' +
' <title>Google Maps JavaScript API v3 Example: Map Simple</title>' +
' <meta name="viewport"' +
' content="width=device-width, initial-scale=1.0, user-scalable=no">' +
' <meta charset="UTF-8">' +
' <style type="text/css">' +
' html, body, #map_canvas {' +
' margin: 0;' +
' padding: 0;' +
' height: 100%;' +
' }' +
' </style>' +
' <script type="text/javascript"' +
' src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>' +
' <script type="text/javascript">' +
' var map;' +
' function initialize() {' +
' var myOptions = {' +
' zoom: 8,' +
' center: new google.maps.LatLng(-34.397, 150.644),' +
' mapTypeId: google.maps.MapTypeId.ROADMAP' +
' };' +
' map = new google.maps.Map(document.getElementById(''map_canvas''),' +
' myOptions);' +
' }' +
' google.maps.event.addDomListener(window, ''load'', initialize);' +
' </script>' +
' </head>' +
' <body>' +
' <div id="map_canvas"></div>' +
' </body>' +
'</html>';
procedure TForm2.FormCreate(Sender: TObject);
var
HTMLStream: TMemoryStream;
begin
WebBrowser1.Navigate('about:blank');
if Assigned(WebBrowser1.Document) then
begin
HTMLStream := TMemoryStream.Create;
try
HTMLStream.WriteBuffer(Pointer(HTMLString)^, Length(HTMLString));
HTMLStream.Seek(0, soFromBeginning);
(WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(HTMLStream));
finally
HTMLStream.Free;
end;
end;
end;
end.