2009-12-15 12 views
5

Dziwny problem. Może ktoś może dać wgląd.Jakoś uszkodzone uchwyty?

  • Scenariusz 1. Mam w pamięci TBitmap, do której zapisuje się, podczas gdy mają miejsce złożone obliczenia, aby obliczyć kolor każdego piksela. Co jakiś czas (zwykle po każdej linii poziomej wypełnionej bitmapą) mapa TBitmap jest rysowana do obrazu w formularzu (image1.Canvas.Draw (0, 0, TBitmap). Większość czasu to działa dobrze, ale zauważyłem jeśli dla każdej linii bitmapowej istnieje wiele powolnych złożonych obliczeń (np. do obliczenia więcej niż 30 sekund lub minuty) to główna forma ma chwilowe "migotanie", które w jakiś sposób wymazuje bitmapę, więc wywołujemy tylko wywołania image.draw najnowszy obliczony linia a pierwsze y linie są wygaszone w mapie bitowej. mam wokół tego blokując bitmapę przed obliczeniami.

  • Scenariusz 2. to jest główny kłopot. piszę do TMemoryStream zamiast bitmapy .Te same transakcje są przeprowadzane w celu obliczenia każdej wartości piksela, a następnie każda wartość piksela jest zapisywana w TMemoryStream z memstream.Write (bytevalue, 1) podczas procesu. Na koniec wszystkich obliczeń zapisuję strumień do bitmapy z memstream.SaveToFile ("whatever.bmp"), a następnie uwalniam strumień z memstream.Free. Jeśli obliczenia są szybkie, strumień zapisuje się bez względu na rozmiar (wykonuję testy z wymiarami 10000x10000).

mogę nawet powiedzieć wynikowy plik będzie uszkodzony jako główne okno aplikacji/formularz ma nieznaczne migotanie jak to jest odmalowane. Kiedy tak się dzieje, to tak, jakby każdy uchwyt do map bitowych i TMemoryStream został zabity/odświeżony, więc istniejące dane są uszkodzone.

Wszelkie pomysły? To naprawdę jest do bani. Zwłaszcza, gdy każdy pojedynczy obraz może zająć godzinę, aby go utworzyć, aby odkryć, że gdy skończy się coś w tle, nastąpiło uszkodzenie mapy bitowej lub TMemoryStream.

Czy mogę zablokować uchwyt TMemoryStream tak, jak potrafię z bitmapą? To może pomóc. Lub jakąś deklarację, aby powiedzieć Delphi "Nie zadzieraj z moimi obiektami, nawet jeśli wygląda na to, że aplikacja trwa zbyt długo"

Czy ktoś zna powód końca w Delphi, który powoduje, że tak się dzieje.

Plik TMemoryStream jest tworzony wewnątrz procedury, która wykonuje wszystkie obliczenia, więc jest obiektem lokalnym. W przypadku wydania bitmapy mapa bitowa była zmienną globalną poza procedurą i tak się stało, więc nie sądzę, że jest to przyczyną.

Jest to również w systemie Windows 7, ale zauważyłem oryginalny problem bitmapy pod Vista.

Aktualizacja 1:

Przepraszamy za nie za pomocą komentarzy, ale nie jest restirction od rozmiaru tekstu ...

W odpowiedzi na Remy (i ktoś czytając to) ...

Pojedynczy gwintowany. W przypadku memorystream działa dobrze dla rozdzielczości 5000x5000, jeśli obliczenia są szybkie, ale nie powiedzie się, jeśli utwory są wolne.

jako podstawowy kod jest wzdłuż linii

SetupMemorystream; 
for y:=0 to height do 
    for x:=0 to width do 
     DoCalcs; 
     SetByteValue; 
    end; 
end; 
SaveStream; 

Jeśli DoCalcs jest stosunkowo szybki wtedy wszystko idzie zgodnie z planem. Jeśli jest wolny, otrzymuję uszkodzenie pliku TMemoryStream, a wynikowa mapa bitowa, w której zapisywany jest strumień, jest uszkodzona.

To było identyczne z używaniem w pamięci TBitmap, dopóki nie odkryłem, że mogę zablokować bitmapę, która zatrzymuje Delphi i/lub Windows ponownie przydziela nowy uchwyt do "kiedy chce", co psuje dane w bitmapie.

To zbyt wielki zbieg okoliczności, aby nie myśleć, że ten sam problem nie ma miejsca w przypadku TMemoryStream i jego obsługi.

Aktualizacja 2:

Jednym z bardziej pomocne może trochę info.

Gdy plik TMemoryStream zapisuje OK, wynikowy plik (dla mapy bitowej 5000x5000) ma rozmiar 75 000,054 bajtów.

Gdy zapisany strumień jest uszkodzony, wydaje się być wartością losową (o wielkości od momentu, w którym uchwyt został uszkodzony, dopóki strumień nie zostanie zapisany). Przykładowe rozmiary to 22 MB i 9 MB.

Kiedy patrzę na wynikowe pliki, to edytor heksadecymalny pokazuje, że początki plików są poprawne z częściami nagłówka, ale końce ogonów zostają w jakiś sposób obcięte.

To jest takie dziwne. W każdym razie mogę absolutnie na pewno przepłukać TMemoryStream po wywołaniu SaveToFile i przed uwolnieniem go?

+2

Czy twój kod jest wielowątkowy? Jeśli nie, to nie ma mowy, że prędkość obliczeń może być causi na problemy, które opisałeś. Prawdopodobnie masz po prostu błędny kod, który zapisuje uszkodzone dane do bitmapy/strumienia. –

+0

Zawsze możesz komentować swoje pytania i odpowiedzi oraz wszelkie odpowiedzi na zadawane pytania, nawet po 1 powtórzeniu. Powinieneś również móc edytować swoje pytanie. –

+0

Strumień pamięci to tylko porcja pamięci zapakowana w klasę. VCL i RTL w żaden sposób nie będą z tym bałagani. Więc twój problem musi być gdzieś w kodzie. – Runner

Odpowiedz

0

Trudno znaleźć taki błąd, po prostu zakładając, co się dzieje. Ponieważ operacja jest tak długa, wystarczy po prostu powtórzyć i poczekać, aż błąd zostanie znaleziony.

Proponuję zalogować się na każdym etapie procesu. Otrzymasz prawdopodobnie ogromny dziennik, ale pokaże ci, gdzie coś pójdzie nie tak. Powtórz ten proces i ulepsz swój log, w ten sposób powinieneś powoli, ale pewnie znaleźć przyczynę problemu.

1

Po zwolnieniu filtru używanego do zapisu wywołanie zamknięcia pliku nie jest sprawdzane pod kątem błędów. Więc twój zapis może się nie udać, być może po wypłukaniu ostatnich bloków twojego dużego pliku i nie będzie żadnego wyjątku.

Niedawno otrzymałem wiadomość: jest w QC 80148. Jednak niewiele można z tym zrobić, ponieważ funkcja Windows CloseHandle prawdopodobnie nie zwróci żadnego błędu.

1
  1. Przed zapisaniem każdego bajtu do strumienia pamięci, ustaw Pojemność na przybliżony rozmiar strumienia bitów, aby często nie zmieniał rozmiaru pamięci.Szybkość ta sprawa się

  2. Chyba trzeba odjąć 1 od wysokości i szerokości na pętli

Cheers

+0

+1, pojemność zmieni wydajność na lepsze, a pętle powinny być najprawdopodobniej "dla y: = 0 do wysokości-1 do". – skamradt

0

Można użyć wywołania API FlushFileBuffers(filestream.Handle) do spłukania TFileStream, ale moja domyślam się, że dzieje się coś innego, co powoduje korupcję, co może być tak proste, jak twoja pętla przechodząca od 0 do szerokości zamiast od 1 do szerokości lub od 0 do szerokości -1 ... trudno powiedzieć bez analizy tego, co twoja robią to, aby zapełnić strumień pamięci.

1

Dzięki za wszystkie wskazówki, chłopaki. Pętle miały poprawne 0 do szerokości-1 w kodzie.

Problemem były zmienne dla szerokości i wysokości, które zostały zmienione w innym miejscu w aplikacji, gdy rozmiar głównego formularza został zmieniony (zazwyczaj śledzą wyświetlany obraz, ale użyłem tych samych zmiennych w tej procedurze do śledzenia szerokość i wysokość bitmapy pamięci memorystycznej.Więc kiedy zostały one zmienione poza pętlami wkręca się i uszkodzone dane wyjściowe.Jak problem ze śledzeniem problemu.Po zlokalizowaniu szerokości i wysokości zmiennych wszystko działa zgodnie z oczekiwaniami. powinienem wiedzieć, że to był mój błąd, a nie problem Delphi